【问题标题】:Partition elimination in GreenplumGreenplum 中的分区消除
【发布时间】:2015-06-30 08:01:12
【问题描述】:

我有这样一个场景:

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

该表由PACKAGE_TYPE 字段分区。假设PACKAGE_TYPE 字段有二十个可能的值。所以有二十个分区,包括BOXCARDDEFAULT分区。运行上述查询时,分区消除正确发生,仅扫描 BOXCARDpartitions。结果很快。

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

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

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

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

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

提前致谢。

【问题讨论】:

  • 分区消除通常发生在查询执行的编译阶段。目前需要的分区列表未知。
  • 谢谢。任何解决方法来完成这项工作?无法对我的查询中的值进行“硬编码”。

标签: sql postgresql partition greenplum


【解决方案1】:

The Postgres manual page on Partitioning 包含此警告

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

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

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

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

【讨论】:

  • 非常感谢。我懂了。我只有一个问题。我尝试动态构建 SQL。但似乎数组没有被编译器识别,我得到这个错误:错误:运算符不是唯一的:未知||字符变化[]
  • 我的执行语句如下所示:ARRVAR character varying[]; ARRVAR := 数组(从 PACKAGE_LIST_TABLE 中选择 PACKAGE_ID);执行 'UPDATE PACKAGE_TYPE SET PACKAGE_DT = CURRENT_DATE WHERE PACKAGE_ID = any('||ARRVAR||')';我错过了什么?如何让数组在动态查询中工作?
  • 该错误与动态查询无关,这是因为您试图将数组连接成一个字符串,而 Postgres 不知道您的意思。我手头没有要检查的环境,但我认为您可以在函数中完全没有动态 SQL 字符串,只需编写 UPDATE PACKAGE_TYPE SET PACKAGE_DT = CURRENT_DATE WHERE PACKAGE_ID = any(ARRVAR);
  • 谢谢。我尝试在函数内部给出直接的 UPDATE 语句。但是该查询所花费的时间类似于在分区列上没有 WHERE 子句的查询。由于查询在函数内部,我无法验证它是否命中所有分区,因为当我运行解释分析时,postgres 没有显示任何关于分区扫描的信息。但是,我知道在查看整体运行时间时并没有消除分区。所以选项要么将其作为动态查询提供,要么附加所有包 id,将其存储在一个字符变量中,然后将其放入 WHERE 子句中。
  • 没关系,我从您的提示中找到了一种方法 - “尝试将数组连接成一个字符串”。我用这个 - CHARVAR := ''''||array_to_string(ARRAY(SELECT PACKAGE_ID FROM PACKAGE_LIST_TABLE), ''',''')||''''; .
猜你喜欢
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
相关资源
最近更新 更多