PostgreSQL/GreenPlum分区消除和左连接
PostgreSQL/GreenPlum partition elimination and left join
是否可以使用分区消除与左外连接到分区 table?
我的理解是,分区消除仅在分区键位于 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)
则它不会进行任何分区消除。
我被要求 post 完整的查询,所以这里有一个精简版(真实的东西很大,有几十列,还有几个 tables,一些大案例报表和机密的客户业务逻辑):
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
是可选的。 None 个 table 已分区。
现在为了分区,我添加了一个新列 voyage_sdd
,它是 voyage.std
的日期部分。我在新日期列上划分事实 tables 和航程 table。查询然后变成这样:
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
成为内部联接。如果我离开最后一行,那么查询仍然有效并且 returns 正确的数据,但它比非分区查询效率低,因为它必须扫描所有分区。如果我让 fact2
未分区,那么我在只有一个小数据集的测试环境中会得到轻微的性能改进,我希望当我们获得更多磁盘 space 和代表时这会有所改善测试中的数据量。
所以重申一下我的问题,我怎样才能对 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)table 是在连接键上分区的,并且由于航程 table 对连接键有约束,所以事实 table分区可以消除。
首先,where (right_table.date_key = '2016-02-02' or right_table.date_key is null)
NULL 的 or
条件可能是阻止分区消除的问题。
其次,针对"how to partition f2"的问题。大多数时候,我总是在 'date' 上进行分区,因为大多数 DW 查询都会有一个谓词来缩小 'date'。就像你在最后一行所做的那样 fact2.voyage_sdd = '2016-02-02'
.
此外,如果符合您的业务逻辑,我会将所有分区列包含在 'join' 列中。在那种情况下,如果优化器支持通过连接动态分区消除,如 GPORCA (http://pivotal.io/big-data/white-paper/optimizing-queries-over-partitioned-tables-in-mpp-systems),那么您可以从中受益。
希望能回答您的问题。
你问的是不可能的。条件 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)
。所以我们不能只局限于那个 table.
如果你真正想要的不是
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)
是否可以使用分区消除与左外连接到分区 table?
我的理解是,分区消除仅在分区键位于 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)
则它不会进行任何分区消除。
我被要求 post 完整的查询,所以这里有一个精简版(真实的东西很大,有几十列,还有几个 tables,一些大案例报表和机密的客户业务逻辑):
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
是可选的。 None 个 table 已分区。
现在为了分区,我添加了一个新列 voyage_sdd
,它是 voyage.std
的日期部分。我在新日期列上划分事实 tables 和航程 table。查询然后变成这样:
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
成为内部联接。如果我离开最后一行,那么查询仍然有效并且 returns 正确的数据,但它比非分区查询效率低,因为它必须扫描所有分区。如果我让 fact2
未分区,那么我在只有一个小数据集的测试环境中会得到轻微的性能改进,我希望当我们获得更多磁盘 space 和代表时这会有所改善测试中的数据量。
所以重申一下我的问题,我怎样才能对 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)table 是在连接键上分区的,并且由于航程 table 对连接键有约束,所以事实 table分区可以消除。
首先,where (right_table.date_key = '2016-02-02' or right_table.date_key is null)
NULL 的 or
条件可能是阻止分区消除的问题。
其次,针对"how to partition f2"的问题。大多数时候,我总是在 'date' 上进行分区,因为大多数 DW 查询都会有一个谓词来缩小 'date'。就像你在最后一行所做的那样 fact2.voyage_sdd = '2016-02-02'
.
此外,如果符合您的业务逻辑,我会将所有分区列包含在 'join' 列中。在那种情况下,如果优化器支持通过连接动态分区消除,如 GPORCA (http://pivotal.io/big-data/white-paper/optimizing-queries-over-partitioned-tables-in-mpp-systems),那么您可以从中受益。
希望能回答您的问题。
你问的是不可能的。条件 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)
。所以我们不能只局限于那个 table.
如果你真正想要的不是
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)