PostgreSQL约束排除不适用于子查询SELECT IN

时间:2016-08-08 11:03:43

标签: sql postgresql constraints partition

在PostgreSQL中使用分区时, master 是主分区表

CREATE TABLE master
(
  _id numeric,
  name character varying
);

并有两个子表

partition_1

CREATE TABLE partition_1
(
  -- _id numeric,
  -- name character varying,
  CONSTRAINT partition_1_check CHECK (_id < 1000)
)    
INHERITS (master);
CREATE INDEX partition_1_id_idx
  ON partition_1
  USING btree
  (_id);

partition_2

CREATE TABLE partition_2
(
  -- _id numeric,
  -- name character varying,
  CONSTRAINT partition_2_check CHECK (_id >= 1000)
)    
INHERITS (master);
CREATE INDEX partition_2_id_idx
  ON partition_2
  USING btree
  (_id);

以及此示例中某些ID(1,3)的表

CREATE TABLE _ids
(
_id numeric NOT NULL,
CONSTRAINT ids_pkey PRIMARY KEY (_id)
)

声明

EXPLAIN SELECT * FROM master WHERE _id IN (SELECT * FROM _ids)
无论_ids是否包含来自partition_1 / 2的元素,

都会产生两个分区的seq扫描。

Hash Semi Join  (cost=39.48..141.14 rows=2621 width=14)
  Hash Cond: (master._id = _ids._id)
  ->  Append  (cost=0.00..62.00 rows=4001 width=14)
        ->  Seq Scan on master  (cost=0.00..0.00 rows=1 width=14)
        ->  Seq Scan on partition_1  (cost=0.00..30.98 rows=1998 width=13)
        ->  Seq Scan on partition_2  (cost=0.00..31.02 rows=2002 width=15)
  ->  Hash  (cost=23.10..23.10 rows=1310 width=32)
        ->  Seq Scan on _ids  (cost=0.00..23.10 rows=1310 width=32)

如果我改用

SELECT * FROM master WHERE _id IN (1,3) 

我得到了理想的结果:

Append  (cost=0.00..17.40 rows=5 width=13)
  ->  Seq Scan on master  (cost=0.00..0.00 rows=1 width=14)
        Filter: (_id = ANY ('{1,3}'::numeric[]))
  ->  Bitmap Heap Scan on partition_1  (cost=8.59..17.40 rows=4 width=13)
        Recheck Cond: (_id = ANY ('{1,3}'::numeric[]))
        ->  Bitmap Index Scan on partition_1_id_idx  (cost=0.00..8.58 rows=4 width=0)
              Index Cond: (_id = ANY ('{1,3}'::numeric[]))

如何让PostgreSQL正确使用约束排除?

注意:我已将constraint_exclusion设置为分区

1 个答案:

答案 0 :(得分:3)

评论太长了。

当Postgres编译该查询时,会选择分区。当您使用常量时,引擎会知道数据所在的位置。当您使用子查询时,Postgres不知道。

因此,使用子查询会阻止引擎利用分区。