改进在 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 查询的主要内容,如果未能解决你的问题,请参考以下文章
pentaho cde在sql查询中包含/排除where子句
SQL - 聚合可能不会出现在 WHERE 子句中,除非它位于 HAVING 子句中包含的子查询中