Flo*_*ian 10 sql-server constraint optimization sql-server-2016
我正在尝试找出提高非常慢查询性能的方法。它有更明显的问题,但我注意到的一件事是 WHERE 子句中的条件之一是 'AND t.data IS NOT NULL' 而表 t 的 'data' 列没有为 NULL 的条目并且确实有一个 NOT NULL 约束。
所以我想知道查询优化器是否能够忽略条件。我的想法是,它不能仅仅因为约束而这样做(因为不能保证它是否是用 NOVALIDATE 创建的),但可能足够“聪明”以使用有关列中 NULL 字段数量的统计信息。
我自己的测试是不确定的,我无法找到有关此主题的任何进一步信息。
Jos*_*ell 18
我的有限测试表明,在以下情况下可以消除“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
Run Code Online (Sandbox Code Playgroud)
它有两列:一列被声明为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');
Run Code Online (Sandbox Code Playgroud)
然后我们可以得到关于这两个查询的估计计划:
SELECT * FROM dbo.Test WHERE DeclareNotNull IS NOT NULL;
SELECT * FROM dbo.Test WHERE DeclaredNull IS NOT NULL;
Run Code Online (Sandbox Code Playgroud)
请注意,扫描中没有“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');
Run Code Online (Sandbox Code Playgroud)
我们得到了第二个查询的估计计划:
聚集索引扫描运算符现在包括一个“谓词”部分,因为检查约束不受信任。