我对 SQL Server 2008(r2) 的行为感到惊讶。
我已经定义了一个带有这样列的表:
ex int not null default 1 check (ex = 1)
我期望像这样的查询
select *
from t20130603_b
where ex = 0
有没有获取行的查询计划,只使用一个常量值(因为 ex = 0 是不可能的)。
但是有(全扫描)。
我得到/做错了什么吗?
我对 SQL Server 2008(r2) 的行为感到惊讶。
我已经定义了一个带有这样列的表:
ex int not null default 1 check (ex = 1)
我期望像这样的查询
select *
from t20130603_b
where ex = 0
有没有获取行的查询计划,只使用一个常量值(因为 ex = 0 是不可能的)。
但是有(全扫描)。
我得到/做错了什么吗?
几种可能性。该计划可能已自动参数化,或者检查约束可能不可信。
CREATE TABLE t20130603_b
(
ex INT NOT NULL DEFAULT 1 CONSTRAINT ck CHECK (ex = 1)
)
/*Plan shows table scan*/
SELECT *
FROM t20130603_b
WHERE ex = 0
在 SQL Server 2012 中,图形计划中的文本显示ex = @1
在以前的版本中尝试了自动参数化(文本为 ),您可能需要查看计划的 XML 版本。因为在编译之前文字0
被替换为参数@1
,所以无法检测到与检查约束的矛盾。
有关自动参数化的更多详细信息,请参见此处。那篇文章提到查询IN Expressions
不会自动参数化。尝试以下
SELECT *
FROM t20130603_b
WHERE ex IN ( 0, 0 )
给出以下计划
该表不再被访问,并被替换为持续扫描。要查看不受信任的约束的问题,您可以尝试。
/*Disable constraint*/
ALTER TABLE t20130603_b
NOCHECK CONSTRAINT ck
/*Re-enable without checking existing data.
Constraint is not trusted*/
ALTER TABLE t20130603_b
CHECK CONSTRAINT ck
SELECT is_not_trusted
FROM sys.check_constraints
WHERE name = 'ck'
SELECT *
FROM t20130603_b
WHERE ex IN ( 0, 0 )
上面又回到了原来的表扫描计划。
/*Correct way of re-enabling constraint*/
ALTER TABLE t20130603_b
WITH CHECK CHECK CONSTRAINT ck
/*Constraint is trusted*/
SELECT is_not_trusted
FROM sys.check_constraints
WHERE name = 'ck'
/*Back to constant scan*/
SELECT *
FROM t20130603_b
WHERE ex IN ( 0, 0 )
在约束再次被信任后,它又回到了持续扫描。