now()函数是获取当前时间,当SQL语句中分区表时间传入now()时,由于SQL下推DN节点执行,优化器在CN节点生成执行计划时,无法进行分区剪枝,导致扫描了所有分区,导致SQL性能下降,SQL并行执行时会引起严重的分区表锁冲突。
针对此问题,建议传入具体值代替now(),或定义一个稳定函数代替now()。
以下是关于该场景的测试情况:
-
准备测试数据:
teledb=# create table t_time_range (f1 bigint, f2 timestamp ,f3 bigint) partition by range (f2) begin (timestamp without time zone '2021-06-01 0:0:0') step (interval '1 month') partitions (12) distribute by shard(f1) to group default_group; CREATE TABLE
-
使用now()时SQL执行计划:
可以看到,SQL被下推到DN节点执行,优化器没有剪枝,扫了所有分区。
teledb=# explain select * from t_time_range where f2<now(); QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- Remote Fast Query Execution (cost=0.00..0.00 rows=0 width=0) Node/s: dn001, dn002, dn003 -> Append (cost=0.00..0.00 rows=0 width=0) -> Seq Scan on t_time_range (partition sequence: 0, name: t_time_range_part_0) (cost=0.00..2.17 rows=30 width=24) Filter: (f2 < now()) -> Seq Scan on t_time_range (partition sequence: 1, name: t_time_range_part_1) (cost=0.00..2.17 rows=30 width=24) Filter: (f2 < now()) -> Seq Scan on t_time_range (partition sequence: 2, name: t_time_range_part_2) (cost=0.00..2.17 rows=30 width=24) Filter: (f2 < now()) -> Seq Scan on t_time_range (partition sequence: 3, name: t_time_range_part_3) (cost=0.00..2.17 rows=30 width=24) Filter: (f2 < now()) -> Seq Scan on t_time_range (partition sequence: 4, name: t_time_range_part_4) (cost=0.00..2.17 rows=30 width=24) Filter: (f2 < now()) -> Seq Scan on t_time_range (partition sequence: 5, name: t_time_range_part_5) (cost=0.00..2.17 rows=30 width=24) Filter: (f2 < now()) -> Seq Scan on t_time_range (partition sequence: 6, name: t_time_range_part_6) (cost=0.00..2.17 rows=30 width=24) Filter: (f2 < now()) -> Seq Scan on t_time_range (partition sequence: 7, name: t_time_range_part_7) (cost=0.00..2.17 rows=30 width=24) Filter: (f2 < now()) -> Seq Scan on t_time_range (partition sequence: 8, name: t_time_range_part_8) (cost=0.00..2.17 rows=30 width=24) Filter: (f2 < now()) -> Seq Scan on t_time_range (partition sequence: 9, name: t_time_range_part_9) (cost=0.00..2.17 rows=30 width=24) Filter: (f2 < now()) -> Seq Scan on t_time_range (partition sequence: 10, name: t_time_range_part_10) (cost=0.00..2.17 rows=30 width=24) Filter: (f2 < now()) -> Seq Scan on t_time_range (partition sequence: 11, name: t_time_range_part_11) (cost=0.00..2.17 rows=30 width=24) Filter: (f2 < now()) (27 rows)
-
自定义一个稳定函数
teledb=# create or replace function get_current_timestamp() returns timestamp as $$ begin return current_timestamp; end; $$ language plpgsql IMMUTABLE; CREATE FUNCTION
-
用自定义的稳定函数代替now()后的执行计划:
可以看到,SQL下推DN节点执行后,优化器成功剪枝,只扫描了2个分区。
teledb=# explain select * from t_time_range where f2<get_current_timestamp(); QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- Remote Fast Query Execution (cost=0.00..0.00 rows=0 width=0) Node/s: dn001, dn002, dn003 -> Append (cost=0.00..0.00 rows=0 width=0) -> Seq Scan on t_time_range (partition sequence: 0, name: t_time_range_part_0) (cost=0.00..11.69 rows=178 width=24) Filter: (f2 < '2021-07-12 11:31:33.639119'::timestamp without time zone) -> Seq Scan on t_time_range (partition sequence: 1, name: t_time_range_part_1) (cost=0.00..11.69 rows=178 width=24) Filter: (f2 < '2021-07-12 11:31:33.639119'::timestamp without time zone) (7 rows)