Greenplum中的分区消除

时间:2015-04-22 14:51:56

标签: sql postgresql partition greenplum

我有这样的场景:

SELECT * FROM PACKAGE WHERE PACKAGE_TYPE IN ('BOX','CARD')

该表由PACKAGE_TYPE字段分区。假设PACKAGE_TYPE字段有20个可能的值。因此,有20个分区,包括BOXCARDDEFAULT分区。运行上述查询时,会正确进行分区排除,并且只扫描BOXCARD分区。结果很快。

但是,当相同的查询写成如下:

SELECT * FROM PACKAGE WHERE PACKAGE_TYPE IN (SELECT PACKAGE_TYPE FROM PACKAGE_LIST_TABLE)PACKAGE_TYPE中的PACKAGE_LIST_TABLE列包含两个值BOXCARD

运行上述查询时,正在扫描所有20个分区。它会降低性能。

似乎编译器无法正确识别第二个查询,因此所有分区都被访问。

要解决此问题的任何变通方法吗?

提前致谢。

1 个答案:

答案 0 :(得分:1)

The Postgres manual page on Partitioning包括此警告

  

约束排除仅在查询的WHERE子句包含常量(或外部提供的参数)时有效。例如,无法优化与CURRENT_TIMESTAMP之类的非不可变函数的比较,因为计划程序无法知道函数值在运行时可能属于哪个分区。

为了消除对分区的搜索,Postgres在创建查询计划时必须知道,该分区中的任何行都不相关。在您的查询中,这仅在子查询完成后才会发生,因此查询必须分成两部分,第二部分仅在第一部分完成后计划。

如果分区在分区列(PACKAGE_TYPE)上包含索引以及约束,则规划器可能选择在每个分区上使用索引扫描,从而导致错误无论如何,分区在运行时被合理有效地消除。 (也就是说,会有20个索引扫描,但每个都需要非常少的资源。)

另一种方法是自己拆分查询,并动态构建SQL。由于SELECT PACKAGE_TYPE FROM PACKAGE_LIST_TABLE只能返回20个不同的值,因此您可以在应用程序或用户定义的函数中选择这些值到数组/集中。然后,您可以像在第一个示例中那样将IN ( ... )子句中的文字作为文字传递(或等效地= ANY(array_expression)),并实现分区消除。