PostgreSQL 约束排除不适用于子查询 SELECT IN
PostgreSQL constraint exclusion not working with subquery SELECT IN
在 PostgreSQL 中使用分区时,其中 master 是主分区 table
CREATE TABLE master
(
_id numeric,
name character varying
);
并且有两个子 table
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) 的 table
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 的元素。
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 设置为分区
分区是在 Postgres 编译该查询时选择的。当您使用常量时,引擎就会知道数据所在的位置。当你使用子查询时,Postgres 并不知道。
因此,使用子查询会阻止引擎利用分区。
在 PostgreSQL 中使用分区时,其中 master 是主分区 table
CREATE TABLE master
(
_id numeric,
name character varying
);
并且有两个子 table
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) 的 table
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 的元素。
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 设置为分区
分区是在 Postgres 编译该查询时选择的。当您使用常量时,引擎就会知道数据所在的位置。当你使用子查询时,Postgres 并不知道。
因此,使用子查询会阻止引擎利用分区。