Sql-Server

常量變數為空時執行計劃不同

  • November 3, 2020

我正在研究一個為變數提供值的場景。當我傳遞 Null 值時,查詢引擎沒有掃描聯接表。根據邏輯查詢處理,首先執行FROM子句,然後執行ONJOIN。但在這種情況下,查詢引擎直接轉到Where子句。當變數的值為 NULL 時,誰能解釋一下行為查詢引擎。我正在使用 SQL Server 2016。

在此處輸入圖像描述

當值改變時

在此處輸入圖像描述

您正在看到一個矛盾檢測的範例。SQL Server 的查詢優化器足夠智能,可以在查詢處理開始時執行一些快速檢查,以確定它是否可以在不做太多(任何?!)工作的情況下使用任何快捷方式返回結果。一種這樣的短路是檢查 where 子句是否包含“不可能”的限制,例如:

WHERE 1=0

或者

WHERE NULL = NULL

SQL Server 看到您正在將某些內容與 進行比較NULL,它總是返回 false,並且只返回一個空的結果集。如果您的WHERE子句中的項目用OR而不是分隔AND,那麼將執行進一步的檢查,您可能看不到常量掃描計劃。

將任何值與NULLusing 進行比較= 總是返回 false。您可能想WHERE @c IS NULL改用。如果您使用該語法重寫查詢,您將看到 SQL Server 實際上“執行”查詢。考慮一下:

IF OBJECT_ID(N'tempdb..#t', N'U') IS NOT NULL DROP TABLE #t;
CREATE TABLE #t 
(
   i int NOT NULL
);

DECLARE @c int = 1;

此查詢的查詢計劃:

SELECT *
FROM #t t
WHERE t.i = 1
   AND @c = NULL;

在此處輸入圖像描述

與此查詢的查詢計劃相比:

SELECT *
FROM #t t
WHERE t.i = 1
   AND @c IS NULL;

在此處輸入圖像描述

比較NULL值的問題也適用於JOIN條件。考慮一下:

IF OBJECT_ID(N'tempdb..#t', N'U') IS NOT NULL DROP TABLE #t;
CREATE TABLE #t 
(
   i int NULL
);

IF OBJECT_ID(N'tempdb..#s', N'U') IS NOT NULL DROP TABLE #s;
CREATE TABLE #s 
(
   i int NULL
);

我將在每個表中插入一行,其值i設置為NULL

INSERT INTO #t (i) VALUES (NULL);
INSERT INTO #s (i) VALUES (NULL);

現在,如果我們嘗試JOIN在“簡單”查詢中對這兩個表進行查詢,我們不會返回任何結果,因為NULL無法與任何東西進行比較,甚至不能與另一個NULL值進行比較!

SELECT *
FROM #t t
   INNER JOIN #s s ON t.i = s.i;

在此處輸入圖像描述

這兩個表都由查詢處理器掃描,如查詢計劃所示:

在此處輸入圖像描述

換句話說,小心使用NULL值。

引用自:https://dba.stackexchange.com/questions/227188