【问题标题】:PostgreSQL/GreenPlum partition elimination and left joinPostgreSQL/GreenPlum 分区消除和左连接
【发布时间】: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


【解决方案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)

【讨论】:

    【解决方案2】:

    首先,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' 所做的那样。

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

    希望能回答您的问题。

    【讨论】:

    • 大家好消息!分区消除仍然通过连接子句起作用。编辑帖子以反映这一点。
    猜你喜欢
    • 2015-06-30
    • 1970-01-01
    • 1970-01-01
    • 2017-02-26
    • 1970-01-01
    • 2011-06-02
    • 2011-03-07
    • 1970-01-01
    • 2013-04-12
    相关资源
    最近更新 更多