【发布时间】:2023-03-18 04:25:02
【问题描述】:
是否可以通过对分区表的左外连接来使用分区消除?
我的理解是分区消除仅在分区键位于 where 子句中时才有效,因此where right_table.date_key = '2016-02-01' 将执行分区消除,但这与左连接不兼容,因为它会消除任何不存在的行right_table。
如果我输入where (right_table.date_key = '2016-02-02' or right_table.date_key is null),那么它不会进行任何分区消除。
我被要求发布完整的查询,所以这里是一个精简版(真实的东西很大,有几十列、几个表、一些大案例语句和机密的客户端业务逻辑):
select voyage.std -- timestamp
, person.name
, fact1.score score_1
, fact2.score score_2
from fact1
join voyage on voyage.voyage_sk = fact1.voyage_sk
join person on person.person_sk = fact1.person_sk
left join fact2 on fact2.person_sk = person.person_sk
where voyage.std = '2016-02-02 14:33:00'
所以fact1 始终存在,但fact2 是可选的。没有一个表是分区的。
现在为了分区,我添加了一个新列voyage_sdd,它是voyage.std 的日期部分。我在新日期列上对事实表和航程表进行分区。然后查询变成这样:
select voyage.std -- timestamp
, person.name
, fact1.score score_1
, fact2.score score_2
from fact1
join voyage on voyage.voyage_sk = fact1.voyage_sk
join person on person.person_sk = fact1.person_sk
left join fact2 on fact2.person_sk = person.person_sk
where voyage.std = '2016-02-02 14:33:00'
and voyage.voyage_sdd = '2016-02-02'
and fact1.voyage_sdd = '2016-02-02'
and fact2.voyage_sdd = '2016-02-02'
最后一行使fact2 成为内连接。如果我省略最后一行,那么查询仍然有效并返回正确的数据,但它比非分区查询效率低,因为它必须扫描所有分区。如果我将fact2 保留为未分区,那么我在只有少量数据集的测试环境中会获得轻微的性能提升,我希望当我们获得更多磁盘空间和测试中具有代表性的数据量时这种情况会有所改善。
所以重申我的问题,我怎样才能对 fact2 进行分区并且仍然有一个左连接?
更新这行得通:
select voyage.std -- timestamp
, person.name
, fact1.score score_1
, fact2.score score_2
from voyage
join person on person.person_sk = fact1.person_sk
join fact1 on fact1.voyage_sk = voyage.voyage_sk and fact1.voyage_sdd = voyage.voyage_sdd
left join fact2 on fact2.person_sk = person.person_sk and fact2.voyage_sdd = voyage.voyage_sdd
where voyage.std = '2016-02-02 14:33:00'
and voyage.voyage_sdd = '2016-02-02'
优化器知道fact2(和fact1)表在连接键上是分区的,并且由于航程表对连接键有约束,所以可以消除事实表分区。
【问题讨论】:
-
显示完整的查询,或者至少显示您提到的连接。
-
EXPLAIN ANALYZE 查询计划也不错。
标签: postgresql greenplum