我对SQL Server 2008(r2)的行为感到惊讶。
我已经定义了一个包含如下列的表:
ex int not null default 1 check (ex = 1)
我期待像
这样的查询select *
from t20130603_b
where ex = 0
要获取没有获取行的查询计划,只使用一个常量值(因为ex = 0是不可能的)。
但有(全扫描)。
我做错了吗?
答案 0 :(得分:1)
有几种可能性。该计划可能已自动参数化或检查约束可能不受信任。
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
替换,因此无法检测到与检查约束的矛盾。
有关自动参数化are here的更多详细信息。该文章提到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 )
再次信任约束后,它将返回恒定扫描。