Ich habe eine dauerhaft berechnete Spalte in einer Tabelle, die einfach aus verketteten Spalten besteht, z
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
);
Dies Comp
ist nicht eindeutig, und D ist das Gültigkeitsdatum jeder Kombination von A, B, C
. Daher verwende ich die folgende Abfrage, um das Enddatum für jede Kombination zu ermitteln A, B, C
(im Grunde genommen das nächste Startdatum für denselben Wert von 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;
Ich habe dann einen Index zur berechneten Spalte hinzugefügt, um diese Abfrage (und auch andere) zu unterstützen:
CREATE NONCLUSTERED INDEX IX_T_Comp_D ON dbo.T (Comp, D) WHERE D IS NOT NULL;
Der Abfrageplan hat mich jedoch überrascht. Ich hätte gedacht, dass der Index für die berechnete Spalte zum Scannen von t1 und t2 verwendet werden könnte , da ich eine WHERE-Klausel habe, die das angibt, D IS NOT NULL
und ich sortiere nach Comp
und verweise nicht auf eine Spalte außerhalb des Index, aber ich sah einen Clustered-Index Scan.
Daher habe ich die Verwendung dieses Index erzwungen, um festzustellen, ob sich ein besserer Plan ergibt:
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;
Welches gab diesen Plan
Dies zeigt, dass eine Schlüsselsuche verwendet wird, deren Details:
Nun laut der SQL-Server Dokumentation:
Sie können einen Index für eine berechnete Spalte erstellen, die mit einem deterministischen, aber ungenauen Ausdruck definiert ist, wenn die Spalte in der Anweisung CREATE TABLE oder ALTER TABLE als PERSISTED gekennzeichnet ist. Dies bedeutet, dass das Datenbankmodul die berechneten Werte in der Tabelle speichert und aktualisiert, wenn andere Spalten, von denen die berechnete Spalte abhängt, aktualisiert werden. Das Datenbankmodul verwendet diese dauerhaften Werte, wenn es einen Index für die Spalte erstellt und wenn in einer Abfrage auf den Index verwiesen wird. Mit dieser Option können Sie einen Index für eine berechnete Spalte erstellen, wenn das Datenbankmodul nicht genau nachweisen kann, ob eine Funktion, die berechnete Spaltenausdrücke zurückgibt, insbesondere eine in .NET Framework erstellte CLR-Funktion, sowohl deterministisch als auch präzise ist.
Wenn also, wie in den Dokumenten angegeben, "das Datenbankmodul die berechneten Werte in der Tabelle speichert" und der Wert auch in meinem Index gespeichert wird, warum ist eine Schlüsselsuche erforderlich, um A, B und C abzurufen, wenn auf sie nicht verwiesen wird die Abfrage überhaupt? Ich gehe davon aus, dass sie zur Berechnung von Comp verwendet werden, aber warum? Warum kann die Abfrage den Index auch verwenden t2
, aber nicht t1
?
Abfragen und DDL auf SQL Fiddle
NB Ich habe SQL Server 2008 mit Tags versehen, da dies die Version ist, auf der sich mein Hauptproblem befindet, aber ich erhalte auch 2012 das gleiche Verhalten.