WHERE 與 HAVING 在非聚合列上。優點/缺點/不相關?
我正在重寫不再提取所有必需數據的查詢。我的問題是關於我從未見過的一種做法,也沒有在 StackExchange 上找到任何專門解決該問題的問題。
我知道該
HAVING
語句的重點是在聚合上引入條件,就像WHERE
在單個行上引入條件一樣。但是,我在這段程式碼中看到的內容HAVING
被用來代替WHERE
聚合查詢。中的條件HAVING
不應用於聚合,而是應用於非聚合列。例如:
SELECT id, filedate, SUM(amount) FROM Sales GROUP BY id, filedate HAVING id = 123 AND filedate = '1/1/2018'
相對於:
SELECT id, filedate, SUM(amount) FROM Sales WHERE id = 123 AND filedate = '1/1/2018' GROUP BY id, filedate
此策略是否存在性能影響或其他優點/缺點?
我沒有嘗試自己執行診斷程序,這不是優先事項,我必須自己做。但是,如果對此沒有明確的答案,我想我可能會。
我關心的是優化器如何查看這個查詢。它是聚合所有數據然後根據
HAVING
子句限制結果集,還是意識到它可以對各個行應用具有條件,因為它們專門引用非聚合列?編輯:對於我的範例查詢和我正在重寫的實際 SQL,計劃是相同的,但是查詢具有相似的複雜性,我還沒有足夠的知識從相同的計劃中得出結論。
中的條件
HAVING
不應用於聚合,而是應用於非聚合列。這裡的問題在於您如何描述該
HAVING
條款適用的內容。該HAVING
子句始終適用於聚合欄位,即聚合後的所有剩餘列。您試圖表明/說該HAVING
子句未應用於任何聚合函式,這是它們通常適用的。但實際上,該HAVING
子句控制該聚合函式的結果,或者在您的第一個範例中,控制分組列的結果。但在這兩種情況下,聚合已經執行。因此,在性能方面(更不用說其他人稍後嘗試更新此程式碼的可讀性),您使用
WHERE
子句過濾到將要聚合的內容,然後使用HAVING
子句過濾掉已經聚合的內容聚合。並且,雖然問題中顯示的簡單測試的結果掩蓋了兩者之間的時間差異(或查詢處理順序中的邏輯位置),使得它們“看起來”在做同樣的事情,如果聚合一堆行只是為了稍後將它們扔掉而在邏輯上它們本可以在儲存/計算聚合之前被消除時並沒有降低效率,我會感到非常驚訝。但是,如果您確實看到這個簡單範例的執行計劃相似,我敢打賭,這僅僅是因為優化器認為將這些HAVING
條件變為現實會更有效WHERE
條件,因為它在執行之前重寫查詢。但在這種情況下,我仍然建議不要以這種方式編寫查詢,因為你會讓優化器花費額外的時間來重寫糟糕的程式碼,而它應該花費時間/CPU 週期來尋找更有效的計劃。@DavidSpillett補充說(在對此答案的評論中):“此外,您依賴查詢規劃器看到優化潛力,它可能不會在更複雜的查詢中或者如果您的程式碼最終移植到另一個數據庫(甚至只是一個舊版本的 SQL Server)”。對於它的價值,即使是 HAVING 子句的 Microsoft文件也表示它
WHERE
在沒有出現時充當子句GROUP BY
。現在文件在 GitHub 上,我最近能夠通過Pull Request #235: Correct and Improvement HAVING 子句對其進行更正。