Greenplum中的分区消除
Partition elimination in Greenplum
我有这样一个场景:
SELECT * FROM PACKAGE WHERE PACKAGE_TYPE IN ('BOX','CARD')
table 由 PACKAGE_TYPE
字段分区。假设 PACKAGE_TYPE
字段有二十个可能的值。所以有二十个分区,包括 BOX
、CARD
和 DEFAULT
分区。当上面的查询是 运行 时,分区消除正确发生并且只有 BOX
和 CARD
分区被扫描。结果很快。
然而,当同一个查询写成这样时:
SELECT * FROM PACKAGE WHERE PACKAGE_TYPE IN (SELECT PACKAGE_TYPE FROM PACKAGE_LIST_TABLE)
,其中 PACKAGE_LIST_TABLE
中的列 PACKAGE_TYPE
包含两个值 BOX
和 CARD
.
当上述查询为运行时,正在扫描所有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 ( ... )
子句中的文字传递,并实现分区消除。
我有这样一个场景:
SELECT * FROM PACKAGE WHERE PACKAGE_TYPE IN ('BOX','CARD')
table 由 PACKAGE_TYPE
字段分区。假设 PACKAGE_TYPE
字段有二十个可能的值。所以有二十个分区,包括 BOX
、CARD
和 DEFAULT
分区。当上面的查询是 运行 时,分区消除正确发生并且只有 BOX
和 CARD
分区被扫描。结果很快。
然而,当同一个查询写成这样时:
SELECT * FROM PACKAGE WHERE PACKAGE_TYPE IN (SELECT PACKAGE_TYPE FROM PACKAGE_LIST_TABLE)
,其中 PACKAGE_LIST_TABLE
中的列 PACKAGE_TYPE
包含两个值 BOX
和 CARD
.
当上述查询为运行时,正在扫描所有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 ( ... )
子句中的文字传递,并实现分区消除。