检查优化的查询计划

时间:2013-06-03 15:03:21

标签: performance sql-server-2008 check-constraints

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

我已经定义了一个包含如下列的表:

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

我期待像

这样的查询
select *
from t20130603_b
where ex = 0

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

我做错了吗?

1 个答案:

答案 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 

Plan 1

在SQL Server 2012中,图形式计划中的文本显示在以前的版本中尝试自动参数化(文本为ex = @1),您可能需要查看计划的XML版本。由于在编译之前文字0被参数@1替换,因此无法检测到与检查约束的矛盾。

有关自动参数化are here的更多详细信息。该文章提到IN Expressions的查询未自动参数化。试试下面的

SELECT *
FROM   t20130603_b
WHERE  ex IN ( 0, 0 )

提供以下计划

enter image description here

不再访问该表,并将其替换为常量扫描。要查看不受信任约束的问题,您可以尝试。

/*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 )

再次信任约束后,它将返回恒定扫描。