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.
FOJNtoLSJNandLASJN
), die dazu führt, dass die Dinge nicht wie erhofft funktionieren und Müll (BaseRow / Checksums) verbleibt, der in einigen Arten von Plänen (z. B. Cursorn) nützlich ist, aber hier nicht benötigt wird.Chk
ist Prüfsumme! Danke, da war ich mir nicht sicher. Ursprünglich dachte ich, es könnte etwas mit Prüfbeschränkungen zu tun haben.Obwohl dies aufgrund der künstlichen Natur Ihrer Testdaten ein Zufall sein könnte, habe ich, wie Sie bereits erwähnt haben, versucht, Folgendes umzuschreiben:
Dies ergab einen guten, kostengünstigen Plan, der Ihren Index verwendete und deutlich niedrigere Lesewerte aufwies als die anderen Optionen (und dieselben Ergebnisse für Ihre Testdaten).
Ich vermute, Ihre realen Daten sind komplizierter, daher kann es einige Szenarien geben, in denen sich diese Abfrage semantisch von Ihrer unterscheidet, aber es zeigt sich manchmal, dass die neuen Funktionen einen echten Unterschied bewirken können.
Ich habe mit einigen abwechslungsreicheren Daten experimentiert und einige passende Szenarien gefunden, andere nicht:
quelle
comp
es sich nicht um eine berechnete Spalte handelt, wird die Sortierung nicht angezeigt.LEAD
Funktion hat genau so funktioniert, wie ich es mir für meine lokale Instanz von 2012 Express gewünscht hätte. Leider war diese kleine Unannehmlichkeit für mich noch kein guter Grund, die Produktionsserver zu aktualisieren ...Als ich versuchte, die gleichen Aktionen auszuführen, erhielt ich die anderen Ergebnisse. Erstens sieht mein Ausführungsplan für eine Tabelle ohne Indizes folgendermaßen aus:
Wie aus dem Clustered Index Scan (t2) hervorgeht, wird das Prädikat verwendet, um die erforderlichen zurückzugebenden Zeilen zu bestimmen (bedingt durch die Bedingung):
Wenn der Index hinzugefügt wurde, unabhängig davon, ob er vom WITH-Operator definiert wurde oder nicht, lautete der Ausführungsplan wie folgt:
Wie wir sehen können, wird der Clustered Index Scan durch den Index Scan ersetzt. Wie wir oben gesehen haben, verwendet der SQL Server die Quellenspalten der berechneten Spalte, um den Abgleich der verschachtelten Abfrage durchzuführen. Während des Clustered-Index-Scan können alle diese Werte gleichzeitig erfasst werden (keine zusätzlichen Vorgänge erforderlich). Wenn der Index hinzugefügt wurde, wird die Filterung der erforderlichen Zeilen aus der Tabelle (in der Hauptauswahl) entsprechend dem Index ausgeführt, aber die Werte der Quellenspalten für die berechnete Spalte
comp
müssen noch abgerufen werden (letzte Operation, verschachtelte Schleife). .Aus diesem Grund wird die Key Lookup-Operation verwendet, um die Daten der Quellenspalten der berechneten abzurufen.
PS Sieht aus wie ein Fehler in SQL Server.
quelle