私は単純に連結された列で構成されているテーブルに永続的な計算列を持っています、例えば
CREATE TABLE dbo.T
(
ID INT IDENTITY(1, 1) NOT NULL CONSTRAINT PK_T_ID PRIMARY KEY,
A VARCHAR(20) NOT NULL,
B VARCHAR(20) NOT NULL,
C VARCHAR(20) NOT NULL,
D DATE NULL,
E VARCHAR(20) NULL,
Comp AS A + '-' + B + '-' + C PERSISTED NOT NULL
);
これComp
は一意ではなく、Dはの各組み合わせの日付から有効A, B, C
であるため、次のクエリを使用してそれぞれの終了日を取得しますA, B, C
(基本的にCompの同じ値の次の開始日)を取得します。
SELECT t1.ID,
t1.Comp,
t1.D,
D2 = ( SELECT TOP 1 t2.D
FROM dbo.T t2
WHERE t2.Comp = t1.Comp
AND t2.D > t1.D
ORDER BY t2.D
)
FROM dbo.T t1
WHERE t1.D IS NOT NULL -- DON'T CARE ABOUT INACTIVE RECORDS
ORDER BY t1.Comp;
次に、このクエリ(およびその他)を支援するために、計算列にインデックスを追加しました。
CREATE NONCLUSTERED INDEX IX_T_Comp_D ON dbo.T (Comp, D) WHERE D IS NOT NULL;
しかし、クエリプランには驚きました。私はそれを示すwhere句を持っているので、D IS NOT NULL
ソートしていると思っていたでしょうComp
ので、インデックスの外側の列を参照していないので、計算列のインデックスを使用してt1とt2をスキャンできると思っていましたが、クラスタ化インデックスを見ましたスキャン。
そこで、このインデックスを使用して、より良い計画が得られるかどうかを確認しました。
SELECT t1.ID,
t1.Comp,
t1.D,
D2 = ( SELECT TOP 1 t2.D
FROM dbo.T t2
WHERE t2.Comp = t1.Comp
AND t2.D > t1.D
ORDER BY t2.D
)
FROM dbo.T t1 WITH (INDEX (IX_T_Comp_D))
WHERE t1.D IS NOT NULL
ORDER BY t1.Comp;
この計画を与えた
これは、キールックアップが使用されていることを示しています。詳細は次のとおりです。
さて、SQL-Serverのドキュメントによると:
列がCREATE TABLEまたはALTER TABLEステートメントでPERSISTEDとマークされている場合、確定的であるが不正確な式で定義された計算列にインデックスを作成できます。つまり、データベースエンジンは計算された値をテーブルに格納し、計算された列が依存する他の列が更新されたときに更新されます。データベースエンジンは、列にインデックスを作成するとき、およびインデックスがクエリで参照されるときに、これらの永続化された値を使用します。このオプションを使用すると、データベースエンジンが計算列式を返す関数、特に.NET Frameworkで作成されたCLR関数が確定的かつ正確であるかどうかを正確に証明できない場合に、計算列にインデックスを作成できます。
したがって、ドキュメントで「データベースエンジンが計算された値をテーブルに格納する」と言っており、その値がインデックスにも格納されている場合、A、B、Cが参照されていないときにキー検索が必要なのはなぜですかクエリはまったく?Compの計算に使用されていると思いますが、なぜですか?また、なぜクエリは上のインデックスを使用することができますt2
が、ない上、t1
?
NBこれは私の主な問題が発生しているバージョンであるため、SQL Server 2008にタグを付けましたが、2012年にも同じ動作をします。