改进在 WHERE 子句中包含数百个字符串的 Netezza SQL 查询

Posted

技术标签:

【中文标题】改进在 WHERE 子句中包含数百个字符串的 Netezza SQL 查询【英文标题】:Improve Netezza SQL Query That Contains Hundreds of Strings in WHERE Clause 【发布时间】:2017-11-21 15:01:04 【问题描述】:

我有一个包含数百个潜在字符串的 WHERE 子句的 Netezza 查询。我很惊讶它可以运行,但它需要时间才能完成,并且偶尔会出错(“客户端回滚的事务”)。这是我的查询的伪代码版本。

SELECT
    TO_CHAR(X.I_TS, 'YYYY-MM-DD') AS DATE,
    X.I_SRC_NM AS CHANNEL,
    X.I_CD AS CODE,
    COUNT(DISTINCT CASE WHEN X.I_FLG = 1 THEN X.UID ELSE NULL) AS WIDGETS

FROM
    (SELECT
        A.I_TS,
        A.I_SRC_NM,
        A.I_CD,
        B.UID,
        B.I_FLG

    FROM
        SCHEMA.DATABASE.TABLE_A A
        LEFT JOIN SCHEMA.DATABASE.TABLE_B B ON A.UID = B.UID

    WHERE
        A.I_TS BETWEEN '2017-01-01' AND '2017-01-15'
        AND B.TAB_CODE IN ('00AV', '00BX', '00C2', '00DJ'...
                           ...
                           ...
                           ...
                           ...
                           ...
                           ...
                           ...)
    ) X

GROUP BY
    X.I_TS,
    X.I_SRC_NM,
    X.I_CD
;

在我的查询中,我将B.TAB_CODE 的结果限制为大约 1,200 个值(超过 10k)。老实说,我很惊讶它完全有效,但大部分时间都有效。

有没有更有效的方法来处理这个问题?

【问题讨论】:

【参考方案1】:

如果IN 子句变得过于繁琐,您可以分多个部分进行查询。创建一个包含 TAB_CODE 集的临时表,然后在 JOIN 中使用它。

WITH tab_codes(tab_code) AS (
 SELECT '00AV' 
 UNION ALL
 SELECT '00BX' 
 --- etc ---
)
SELECT
  TO_CHAR(X.I_TS, 'YYYY-MM-DD') AS DATE,
  X.I_SRC_NM AS CHANNEL,
  --- etc ---
  INNER JOIN tab_codes Q ON B.TAB_CODES = Q.tab_code

如果您想进一步提高性能,请考虑使用真正的临时表 (CTAS)

【讨论】:

这实际上比我的查询花费了更多时间。在使用内部查询的示例查询中,我的版本需要 84 秒才能完成,而这需要 298 秒。我不完全明白为什么,但我现在正在研究使用 CTAS 的版本。 使用SELECT tab_code 作为内部查询是否获得相同的性能? 我现在已经修改了很多。内部查询的执行速度也更慢,但它没有一次超时。以前我的查询会超时 4 次中的 3 次。我对 SQL 不够熟悉,无法说明为什么它需要更多时间,但查询每个会话返回约 10M 行,也许返回这么多行需要更多时间,因为我没有要求 SQL 聚合结果? 【参考方案2】:

我们已经看到这样的情况:CTAS 将原始表“更便宜”地分配给另一个表,根据您的主要条件分发,然后改为查询该表。

【讨论】:

【参考方案3】:

    如果我猜对了,X.I_TS 实际上是一个“时间戳”,因此我希望它每天包含许多不同的值。你能证实吗? 如果我是对的,查询可能会受益于将“group by X.I._TS,...”更改为“group by 1,...”

    此外,'Count(Distinct Case...' 不能返回 1 或 NULL 以外的任何值。你能确认一下吗? 如果我是对的,您可以通过将其更改为“MAX(Case...”) 来摆脱昂贵的“DISTINCT”

你能跟着我吗:)

【讨论】:

以上是关于改进在 WHERE 子句中包含数百个字符串的 Netezza SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

如何在rails的where子句中包含if条件

短路逻辑评估运算符

pentaho cde在sql查询中包含/排除where子句

SQL - 聚合可能不会出现在 WHERE 子句中,除非它位于 HAVING 子句中包含的子查询中

在 Hibernate/JPA Generated UPDATE Query 的 Where 子句中包含附加列

使用一个 WHERE 子句更新多个表