Greenplum中的分区消除

Partition elimination in Greenplum

我有这样一个场景:

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

table 由 PACKAGE_TYPE 字段分区。假设 PACKAGE_TYPE 字段有二十个可能的值。所以有二十个分区,包括 BOXCARDDEFAULT 分区。当上面的查询是 运行 时,分区消除正确发生并且只有 BOXCARD 分区被扫描。结果很快。

然而,当同一个查询写成这样时:

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

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

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

有什么解决方法可以解决这个问题?

提前致谢。

The Postgres manual page on Partitioning 包含此警告

Constraint exclusion only works when the query's WHERE clause contains constants (or externally supplied parameters). For example, a comparison against a non-immutable function such as CURRENT_TIMESTAMP cannot be optimized, since the planner cannot know which partition the function value might fall into at run time.

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

如果分区包括分区列 (PACKAGE_TYPE) 上的索引以及约束,规划器 可以 选择对每个分区使用索引扫描,导致不正确的分区无论如何在运行时被合理有效地消除。 (也就是说,会有 20 次索引扫描,但每次都需要很少的资源。)

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