PostgreSQL / GreenPlum分区消除和左连接

时间:2016-02-03 13:57:00

标签: postgresql greenplum

是否可以将分区消除与左外连接一起使用到分区表?

我的理解是分区消除仅在分区键位于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)表在连接键上是分区的,并且由于voyage表对连接键有约束,因此可以消除事实表分区。

2 个答案:

答案 0 :(得分:1)

首先,where (right_table.date_key = '2016-02-02' or right_table.date_key is null) NULL上的or条件可能是阻止分区消除的问题。

第二,关于"如何划分f2"的问题。大多数时候,我总是在“约会”上进行分区,因为大多数DW查询都会有一个谓词来缩小日期'。就像你在最后一行fact2.voyage_sdd = '2016-02-02'所做的那样。

此外,我会在' join'中包含所有分区列。列如果符合您的业务逻辑。在这种情况下,如果优化器支持通过连接消除动态分区,例如GPORCA(http://pivotal.io/big-data/white-paper/optimizing-queries-over-partitioned-tables-in-mpp-systems),那么您可以从中受益。

希望能回答你的问题。

答案 1 :(得分:1)

你提出的问题是不可能的。条件where (right_table.date_key = '2016-02-02' or right_table.date_key is null)在其他方面表示The date is '2016-02-02' or no other record exists)。因此,我们不能仅限于那一张桌子。

如果你真正想要的不是 left join fact2 on fact2.person_sk = person.person_sk and fact2.voyage_sdd = '2016-02-02'

您可以做的最好的方法是尝试以另一种方式编写查询来获得更好的计划,例如:

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
   AND fact2.voyage_sdd = '2016-02-02'
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' OR NOT EXISTS (SELECT * FROM fact2 WHERE fact2.person_sk = person.person_sk)