使用 WHERE NOT IN 子選擇子句提高性能
在以下查詢中,我必須計算每個客戶的交易。但是,我必須從結果集中完全排除交易超過一年的客戶。
查詢優化器不應該足夠聰明,只為每個客戶評估一次存在嗎?
--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
我的查詢計劃中沒有自然。此查詢的執行就像數據庫為每個事務執行存在子句,而不是為每個客戶執行它。
GROUP BY
如果我刪除子查詢中的 ,性能是相同的。有沒有更好的方法來做到這一點,以便我可以從數據庫中獲得更好的性能?如果可能的話,希望一個簡單的
SELECT
查詢能夠避免 CTE(這會帶來其他挑戰)。由於其他
GROUP BY
條件(此處未顯示),我無法簡單地檢查MIN(DATED)
,我真的需要執行另一個查詢。
LEFT OUTER JOIN
對於這樣的查詢,執行 a而不是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
(注意:我不熟悉火鳥,所以上面的語法可能需要調整,但應該說明這一點)
如果沒有匹配中的每一
WHERE t2.CUSTID IS NULL
行,將為找到的每個匹配輸出一次,而沒有匹配的行將輸出一次,但從該對像中選擇的任何列都設置為 NULL。然後該子句篩選出匹配項。t1``t2``t2``t2``WHERE
取決於數據庫引擎的能力,特別是如果參考對象(
CUST_TRX
此處應用了過濾器)中的數據量很大,這可能比WHERE <something> NOT IN
or選項效率低得多WHERE NOT EXISTS
,因此在使用該方法之前首先對實際數據集進行基準測試。在查詢計劃者沒有註意到WHERE NOT IN
可以更有效地執行這種安排的情況下,它通常與 MS SQL Server 一起工作效率更高。此外,如果您這樣做,請在程式碼(和/或支持文件)中留下評論,說明您這樣做是等效的,
WHERE <something> NOT IN
或者WHERE NOT EXISTS
您希望更有效。您會記住它,並且有經驗的 SQL 人員會辨識該模式,但是查看程式碼的其他人可能不會立即理解其意圖/原因並將其轉回使用WHERE NOT EXISTS
,因為這樣讀起來比英文句子更好。