我在Postgres 11数据库中有两个表:
client table
--------
client_id integer
client_name character_varying
file table
--------
file_id integer
client_id integer
file_name character_varying
客户端表未分区,文件表由client_id分区(按列表分区)。将新客户端插入客户端表后,触发器将为文件表创建新分区。文件表具有外键约束,该外键约束引用client_id上的客户机表。
当我执行此SQL(c.client_id = 1)时,一切似乎都很好:
explain
select *
from client c
join file f using (client_id)
where c.client_id = 1;
使用分区修剪,仅扫描分区file_p1:
Nested Loop (cost=0.00..3685.05 rows=100001 width=82)
-> Seq Scan on client c (cost=0.00..1.02 rows=1 width=29)
Filter: (client_id = 1)
-> Append (cost=0.00..2684.02 rows=100001 width=57)
-> Seq Scan on file_p1 f (cost=0.00..2184.01 rows=100001 width=57)
Filter: (client_id = 1)
但是当我使用诸如“ where c.client_name ='test'”之类的where子句时,数据库将扫描所有分区,并且无法识别出,client_name“ test”等于client_id 1 ::
explain
select *
from client c
join file f using (client_id)
where c.client_name = 'test';
执行计划:
Hash Join (cost=1.04..6507.57 rows=100001 width=82)
Hash Cond: (f.client_id = c.client_id)
-> Append (cost=0.00..4869.02 rows=200002 width=57)
-> Seq Scan on file_p1 f (cost=0.00..1934.01 rows=100001 width=57)
-> Seq Scan on file_p4 f_1 (cost=0.00..1934.00 rows=100000 width=57)
-> Seq Scan on file_pdefault f_2 (cost=0.00..1.00 rows=1 width=556)
-> Hash (cost=1.02..1.02 rows=1 width=29)
-> Seq Scan on client c (cost=0.00..1.02 rows=1 width=29)
Filter: ((name)::text = 'test'::text)
因此,对于此SQL,将扫描文件表中的alle分区。
因此,每个选择都应该使用对表进行分区的列?数据库是否无法偏离分区修剪条件?
编辑:要添加一些信息:
过去,我大多数时候都在使用Oracle数据库。
执行计划会是这样
这也是我在Postgresql中所期望的。
The documentation指出可以对动态分区进行修剪
(...)在实际执行查询计划期间。此处也可以执行分区修剪以使用仅在实际查询执行期间才知道的值来删除分区。这包括来自子查询的值和来自执行时参数的值,例如来自参数化嵌套循环联接的值。
如果我理解正确,它适用于准备好的语句或带有子查询的查询,这些查询或查询将分区键值作为参数。使用explain analyse
查看动态修剪(我的样本数据在三个分区中包含一百万行):
explain analyze
select *
from file
where client_id = (
select client_id
from client
where client_name = 'test');
Append (cost=25.88..22931.88 rows=1000000 width=14) (actual time=0.091..96.139 rows=333333 loops=1)
InitPlan 1 (returns $0)
-> Seq Scan on client (cost=0.00..25.88 rows=6 width=4) (actual time=0.040..0.042 rows=1 loops=1)
Filter: (client_name = 'test'::text)
Rows Removed by Filter: 2
-> Seq Scan on file_p1 (cost=0.00..5968.66 rows=333333 width=14) (actual time=0.039..70.026 rows=333333 loops=1)
Filter: (client_id = $0)
-> Seq Scan on file_p2 (cost=0.00..5968.68 rows=333334 width=14) (never executed)
Filter: (client_id = $0)
-> Seq Scan on file_p3 (cost=0.00..5968.66 rows=333333 width=14) (never executed)
Filter: (client_id = $0)
Planning Time: 0.423 ms
Execution Time: 109.189 ms
注意,对分区p2和p3的扫描为never executed
。
回答您的确切问题,在问题中描述的具有联接的查询中的分区修剪未在Postgres中实现(是吗?)