You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 00:03:20