jca*_*314 4 performance execution-plan subquery firebird query-performance
在以下查询中,我必须为每个客户计算交易。但是,我必须从结果集中完全排除交易时间超过一年的客户。
查询优化器不应该足够聪明,只为每个客户评估一次存在吗?
--Count transactions on customers that are less than 1 year old
SELECT t1.CUSTID, COUNT(*)
FROM CUST_TRX t1
WHERE NOT EXISTS (
SELECT FIRST 1 1
FROM CUST_TRX t2
WHERE
t2.CUSTID = t1.CUSTID AND
t2.DATED < CURRENT_DATE - 365
GROUP BY t2.CUSTID
)
GROUP BY t1.CUSTID
Run Code Online (Sandbox Code Playgroud)
我的查询计划中没有自然。此查询的执行就像数据库为每个事务运行存在子句,而不是为每个客户运行它。如果我删除GROUP BY
子查询中的,则性能相同。
有没有更好的方法来做到这一点,以便我可以从数据库中获得更好的性能?SELECT
如果可能的话,希望一个简单的查询能够避免 CTE(这会带来其他挑战)。
由于其他GROUP BY
条件(此处未显示),我无法简单地检查MIN(DATED)
,我确实需要执行另一个查询。
对于这样的查询,执行LEFT OUTER JOIN
而不是NOT EXISTS
样式检查通常更有效,它通常意味着完整的索引扫描(或没有正确索引的表扫描),但主表中有很多行,这是较少的比大量索引查找(从主表返回的每一行在引用表上查找一个)昂贵,否则会导致. 一些查询规划器非常善于发现这种等价性,并在它是更好的选择时使用替代计划,但在您的情况下听起来并没有发生这种情况。
尝试类似:
SELECT t1.CUSTID, COUNT(*)
FROM CUST_TRX t1
LEFT OUTER JOIN
CUST_TRX t2
ON t2.CUSTID=t1.CUSTID
AND t2.DATED<CURRENT_DATE-365
WHERE t2.CUSTID IS NULL
GROUP BY t1.CUSTID
Run Code Online (Sandbox Code Playgroud)
(注意:我不熟悉 firebird,所以上面的语法可能需要调整,但应该说明这一点)
没有匹配项的WHERE t2.CUSTID IS NULL
每一行将t1
在t2
每个匹配项中输出一次t2
,没有匹配项的t2
将输出一次,但从该对象中选择的任何列都设置为 NULL。WHERE
然后该子句筛选出匹配项。
取决于DB发动机的能力,特别是如果数据中的参考对象(该量CUST_TRX
与施加在这里过滤器)是巨大的,这可能是显著少比效率WHERE <something> NOT IN
或WHERE NOT EXISTS
选项,因此基准在真实数据组第一使用该方法之前。在查询计划器没有注意到WHERE NOT IN
可以更有效地执行这种安排的情况下,使用 MS SQL Server通常会更有效。
此外,如果您这样做,请在代码(和/或支持文档)中留下评论,说明您正在这样做,WHERE <something> NOT IN
或者WHERE NOT EXISTS
您希望这样做更有效。您会记住它,并且有经验的 SQL 人员会识别出该模式,但是查看代码的其他人可能不会立即理解其意图/原因并将其翻转回使用WHERE NOT EXISTS
以确保清晰,因为这样读起来更像英文句子。
归档时间: |
|
查看次数: |
7679 次 |
最近记录: |