Sql-Server
常量變數為空時執行計劃不同
我正在研究一個為變數提供值的場景。當我傳遞 Null 值時,查詢引擎沒有掃描聯接表。根據邏輯查詢處理,首先執行FROM子句,然後執行ON和JOIN。但在這種情況下,查詢引擎直接轉到Where子句。當變數的值為 NULL 時,誰能解釋一下行為查詢引擎。我正在使用 SQL Server 2016。
當值改變時
您正在看到一個矛盾檢測的範例。SQL Server 的查詢優化器足夠智能,可以在查詢處理開始時執行一些快速檢查,以確定它是否可以在不做太多(任何?!)工作的情況下使用任何快捷方式返回結果。一種這樣的短路是檢查 where 子句是否包含“不可能”的限制,例如:
WHERE 1=0
或者
WHERE NULL = NULL
SQL Server 看到您正在將某些內容與 進行比較
NULL
,它總是返回 false,並且只返回一個空的結果集。如果您的WHERE
子句中的項目用OR
而不是分隔AND
,那麼將執行進一步的檢查,您可能看不到常量掃描計劃。將任何值與
NULL
using 進行比較=
總是返回 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
值。