執行計划--WHERE條件的先后順序對執行計划的影響


在編寫SQL時,會建議將選擇性高(過濾數據多)的條件放到WHERE條件的前面,這是為了讓查詢優化器優先考慮這些條件,減少生成最優(或相對最優)的執行計划的時間,但最終的執行計划生成過濾順序還是決定這些條件的選擇性與判斷bool值的容易程度

測試代碼:

GO
SELECT *
INTO #T1
FROM sys.all_columns
GO
SELECT *
INTO #T2
FROM sys.all_columns
GO
SELECT *
INTO #T3
FROM sys.all_columns
GO
SET STATISTICS IO ON
SET STATISTICS TIME ON
GO
SELECT * FROM #T1 AS T1
WHERE T1.[object_id]=3
AND (SELECT COUNT(1) FROM #T2 AS T2 WHERE T2.column_id>T1.column_id)>1

SELECT * FROM #T1 AS T1
WHERE (SELECT COUNT(1) FROM #T2 AS T2 WHERE T2.column_id>T1.column_id)>1
AND T1.[object_id]=3

執行計划:

可以從查詢計划看出,無論T1.[object_id]=3在何處,其計算bool值相對簡單,而(SELECT COUNT(1) FROM #T2 AS T2 WHERE T2.column_id>T1.column_id)>1 需要訪問其他表,因此執行優化器優先執行T1.[object_id]=3,在滿足T1.[object_id]=3為ture時再堅持行是否滿足(SELECT COUNT(1) FROM #T2 AS T2 WHERE T2.column_id>T1.column_id)>1。

 

但對於以下查詢:

SELECT * FROM #T1 AS T1
WHERE (SELECT COUNT(1) FROM #T3 AS T3 WHERE T3.[object_id]>T1.[object_id])<1
AND (SELECT COUNT(1) FROM #T2 AS T2 WHERE T2.column_id>T1.column_id)>1


SELECT * FROM #T1 AS T1
WHERE  (SELECT COUNT(1) FROM #T2 AS T2 WHERE T2.column_id>T1.column_id)>1
AND (SELECT COUNT(1) FROM #T3 AS T3 WHERE T3.[object_id]>T1.[object_id])<1

執行計划:

執行統計:

(25 row(s) affected)
Table 'Worktable'. Scan count 29, logical reads 36813, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#T3_________________________________________________________________________________________________________________00000000000C'. Scan count 4, logical reads 80, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#T1_________________________________________________________________________________________________________________000000000009'. Scan count 5, logical reads 59, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#T2_________________________________________________________________________________________________________________00000000000A'. Scan count 1, logical reads 59, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 111 ms,  elapsed time = 331 ms.

(25 row(s) affected)
Table '#T1_________________________________________________________________________________________________________________000000000009'. Scan count 5, logical reads 59, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 10731, logical reads 87653, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#T3_________________________________________________________________________________________________________________00000000000C'. Scan count 4, logical reads 236, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#T2_________________________________________________________________________________________________________________00000000000A'. Scan count 1, logical reads 59, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 219 ms,  elapsed time = 281 ms.
View Code

 

條件 (SELECT COUNT(1) FROM #T2 AS T3 WHERE T3.[object_id]>T1.[object_id])<1 能過濾掉大部分數據,而(SELECT COUNT(1) FROM #T3 AS T2 WHERE T2.column_id>T1.column_id)>1不能過濾任何數據,因此如果優先執行(SELECT COUNT(1) FROM #T3 AS T2 WHERE T2.column_id>T1.column_id)>1,則會大大減少判斷(SELECT COUNT(1) FROM #T2 AS T2 WHERE T2.column_id>T1.column_id)>1的次數,從而提高查詢速度,但SQL Server無法推斷出該結論,因此只能順序判斷WHERE 條件。

 

 

 

總結:雖然在很多情況下SQL Sever引擎能幫助我們判定 WHERE 條件后的執行順序,但我們仍應該將選擇性高(過濾數據多)的條件放置在 WHERE 語句中的前面,尤其對於復雜的SQL 語句,應仔細分析測試。

 

你比SQL SERVER 更了解你的數據!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM