Sql-Server
如果列具有 NOT NULL 約束,查詢優化器是否能夠優化 IS NOT NULL 條件?
我正在嘗試找出方法來提高非常慢的查詢的性能。它有更明顯的問題,但我注意到的一件事是 WHERE 子句中的條件之一是 ‘AND t.data IS NOT NULL’ 而表 t 的 ‘data’ 列沒有為 NULL 的條目並且確實有一個 NOT NULL 約束。
所以我想知道查詢優化器是否能夠忽略該條件。我的想法是,它不能僅僅因為約束而做到這一點(因為不能保證它是否是使用 NOVALIDATE 創建的),但可能足夠“聰明”以使用有關列中 NULL 欄位數量的統計資訊。
我自己的測試沒有定論,我無法找到有關此主題的任何進一步資訊。
我有限的測試表明,如果出現以下情況,可以消除“IS NOT NULL”謂詞:
- 該列
NOT NULL
在表定義中聲明,或- 該列受到活動的、受信任的檢查約束的保護,不會出現空值
這是一個簡單的測試表:
CREATE TABLE dbo.Test ( Id int IDENTITY(1,1) NOT NULL, DeclareNotNull int NOT NULL, DeclaredNull int NULL, CONSTRAINT PK_Test PRIMARY KEY (Id), CONSTRAINT CK_DeclaredNull CHECK (DeclaredNull IS NOT NULL) ); GO INSERT INTO dbo.Test (DeclareNotNull, DeclaredNull) SELECT v.[number], v.[number] FROM master.dbo.spt_values v WHERE v.[number] IS NOT NULL; GO
它有兩列:一列被聲明為
NOT NULL
,另一列被聲明NULL
但有一個檢查約束。兩列都沒有任何帶NULL
值的行。我們可以像這樣驗證檢查約束:
SELECT cs.[name], cs.[type_desc], cs.is_disabled, cs.is_not_trusted FROM sys.check_constraints cs WHERE cs.parent_object_id = OBJECT_ID(N'dbo.Test');
然後我們可以得到關於這兩個查詢的估計計劃:
SELECT * FROM dbo.Test WHERE DeclareNotNull IS NOT NULL; SELECT * FROM dbo.Test WHERE DeclaredNull IS NOT NULL;
請注意,掃描中沒有“Predicate”或“Seek Predicate”部分,或執行計劃中的其他過濾器運算符。在這兩種情況下都刪除了空檢查。
如果我們禁用檢查約束:
ALTER TABLE dbo.Test NOCHECK CONSTRAINT CK_DeclaredNull; GO SELECT cs.[name], cs.[type_desc], cs.is_disabled, cs.is_not_trusted FROM sys.check_constraints cs WHERE cs.parent_object_id = OBJECT_ID(N'dbo.Test');
我們得到了第二個查詢的估計計劃:
聚集索引掃描運算符現在包括一個“謂詞”部分,因為檢查約束不受信任。