1

我对 SQL Server 2008(r2) 的行为感到惊讶。

我已经定义了一个带有这样列的表:

ex int not null default 1 check (ex = 1)

我期望像这样的查询

select *
from t20130603_b
where ex = 0

有没有获取行的查询计划,只使用一个常量值(因为 ex = 0 是不可能的)。
但是有(全扫描)。

我得到/做错了什么吗?

4

1 回答 1

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,所以无法检测到与检查约束的矛盾。

有关自动参数化的更多详细信息,请参见此处。那篇文章提到查询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 )

在约束再次被信任后,它又回到了持续扫描。

于 2013-06-03T18:50:10.743 回答