2025年12月29日 星期一

[研究]SQL Server 中 WHERE 的第一個條件不符,後面條件是否會再檢查 ?

[研究]SQL Server 中 WHERE 的第一個條件不符,後面條件是否會再檢查 ?

2025-12-29

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 20.2

********************************************************************************

SQL Server,TSQL 中 WHERE 的第一個條件不符,後面條件是否會再檢查 ? WHY ? 參考資料來源 ?

ChatGPT

你問的問題涉及 SQL Server 的 WHERE 條件短路(short-circuit evaluation)。我們一步步分析:

1️⃣ T-SQL WHERE 的邏輯

假設有一個查詢:

SELECT *
FROM MyTable
WHERE Condition1 AND Condition2;

問題:如果 Condition1 為 FALSE,Condition2 會不會被評估?

2️⃣ SQL Server 的實際行為

SQL 標準(ANSI SQL)並沒有規定 WHERE 條件的評估順序,也沒有要求短路。

換句話說,SQL 引擎可以自由決定先檢查哪個條件,或者同時檢查多個條件。

SQL Server 實務

SQL Server 通常不保證短路,即使你的第一個條件是 FALSE,也不一定會停止檢查後面的條件。

實務中,如果 WHERE 條件中有可能產生錯誤(例如除以 0、函數呼叫 null 等),就可能在「本來應該不會檢查的條件」發生錯誤。

例子:

SELECT *
FROM MyTable
WHERE 1 = 0 AND 1/0 = 1;

如果 SQL Server 保證短路,這條查詢應該不會錯,因為 1=0 為 FALSE,不會檢查 1/0。

但在 SQL Server 中執行時,仍然會拋出除以 0 的錯誤,表示 SQL Server 沒有保證短路。

3️⃣ 為什麼 SQL Server 不保證短路?

原因在於 SQL Server 的 查詢優化器(Query Optimizer)

查詢優化器會重新排列、合併、拆分條件來找出最有效率的執行計劃。

條件的評估順序可能與你寫的順序完全不同。

這樣做是為了 提高效率,尤其在大量資料時,優化器會考慮索引使用、統計資料、表的大小等因素。

因此,你不能依賴 WHERE 條件的順序來避免後面的錯誤或提高效率。

4️⃣ 正確做法

如果某個條件可能會出錯(例如除以 0 或 NULL 操作),要用 CASE WHEN 或 ISNULL/NULLIF 來避免:

SELECT *
FROM MyTable
WHERE Condition1 AND 
      (CASE WHEN SafeCheck = 0 THEN 0 ELSE 1/ SafeCheck END) = 1;

或者分兩步:

SELECT *
FROM MyTable
WHERE Condition1
  AND SafeCheck <> 0
  AND 1 / SafeCheck = 1;

這樣就不依賴短路。

5️⃣ 官方資料來源

Microsoft Docs — WHERE Clause

"The order in which the conditions are evaluated is not guaranteed."

https://learn.microsoft.com/zh-tw/sql/t-sql/queries/select-transact-sql?view=sql-server-ver16

https://learn.microsoft.com/en-us/sql/t-sql/queries/select-transact-sql?view=sql-server-ver16

Stack Overflow 常見討論:

SQL Server does not guarantee short-circuit evaluation in WHERE clauses.

✅ 總結

  • SQL Server 不保證 WHERE 條件的短路,第一個條件不符合時,後面的條件 可能還是會被檢查。
  • 原因:查詢優化器為了效率,會重新安排評估順序。
  • 若條件可能會出錯,必須顯式處理(如 CASE 或額外判斷),不要依賴順序。

(完)

相關

沒有留言:

張貼留言