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 

プラン1

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 に答える