PostgreSQL分区表使用VALUES子句INSERT时执行计划是否遍历全部分区?
PostgreSQL 大量分区表的 INSERT 与 SELECT 执行计划差异
在 PostgreSQL 中,当表存在大量分区(例如 10000 个)时,执行 SELECT 操作可能会遇到性能问题:执行计划可能会包含所有分区。即使只需要访问单个分区,由于**通用计划(generic plan)**的存在,也可能触发这种情况。以下是 4 个分区的示例,以及直接查询单个分区的规避方法:
SELECT 执行计划示例
创建分区表与分区
CREATE TABLE tst_tt ( c1 int4 NOT NULL, c2 text NOT NULL ) PARTITION BY LIST (c1); CREATE TABLE tst_tt_1 PARTITION OF tst_tt FOR VALUES IN (1); CREATE TABLE tst_tt_2 PARTITION OF tst_tt FOR VALUES IN (2); CREATE TABLE tst_tt_3 PARTITION OF tst_tt FOR VALUES IN (3); CREATE TABLE tst_tt_default PARTITION OF tst_tt DEFAULT;
查询整个分区表
explain select * from tst_tt;
执行计划:
Append (cost=0.00..116.20 rows=5080 width=36) -> Seq Scan on tst_tt_1 (cost=0.00..22.70 rows=1270 width=36) -> Seq Scan on tst_tt_2 (cost=0.00..22.70 rows=1270 width=36) -> Seq Scan on tst_tt_3 (cost=0.00..22.70 rows=1270 width=36) -> Seq Scan on tst_tt_default tst_tt_4 (cost=0.00..22.70 rows=1270 width=36)
直接查询单个分区
explain select * from tst_tt_1;
执行计划:
Seq Scan on tst_tt_1 (cost=0.00..22.70 rows=1270 width=36)
预编译语句查询(自定义计划)
prepare plan_a as select * from tst_tt where c1 = $1; explain execute plan_a(3);
执行计划:
Seq Scan on tst_tt_3 tst_tt (cost=0.00..25.88 rows=6 width=36) Filter: (c1 = 3)
强制使用通用计划的预编译查询
set plan_cache_mode='force_generic_plan'; explain execute plan_a(3);
执行计划:
Append (cost=0.00..103.62 rows=24 width=36) Subplans Removed: 3 -> Seq Scan on tst_tt_3 tst_tt_1 (cost=0.00..25.88 rows=6 width=36) Filter: (c1 = $1)
正式问题:VALUES 子句 INSERT 是否会涉及全部分区?
当使用 VALUES 子句执行 INSERT 操作(例如插入 10 行数据)时,执行计划是否会涉及所有 10000 个分区?测试显示,使用 VALUES 子句的 INSERT 似乎不受该问题影响,无需生成包含全部分区的执行计划即可完成操作,测试示例如下:
直接插入到分区表
explain insert into tst_tt values (1,'a'),(2,'b'),(999,'default');
执行计划:
Insert on tst_tt (cost=0.00..0.04 rows=0 width=0) -> Values Scan on "*VALUES*" (cost=0.00..0.04 rows=3 width=36)
直接插入到单个分区
explain insert into tst_tt_1 values (1,'a'),(1,'a');
执行计划:
Insert on tst_tt_1 (cost=0.00..0.03 rows=0 width=0) -> Values Scan on "*VALUES*" (cost=0.00..0.03 rows=2 width=36)
预编译语句插入(自定义计划)
prepare plan as insert into tst_tt values ($1,'a'),($2,'b'),($3,'default'); explain execute plan(1,2,999);
执行计划:
Insert on tst_tt (cost=0.00..0.04 rows=0 width=0) -> Values Scan on "*VALUES*" (cost=0.00..0.04 rows=3 width=36)
强制使用通用计划的预编译插入
set plan_cache_mode='force_generic_plan'; explain execute plan(1,2,999);
执行计划:
Insert on tst_tt (cost=0.00..0.04 rows=0 width=0) -> Values Scan on "*VALUES*" (cost=0.00..0.04 rows=3 width=36)
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

