Die konstanten Scans erzeugen jeweils eine einzelne speicherinterne Zeile ohne Spalten. Der obere Berechnungsskalar gibt eine einzelne Zeile mit 3 Spalten aus
Expr1005 Expr1006 Expr1004
----------- ----------- -----------
NULL NULL 60
Der untere Berechnungsskalar gibt eine einzelne Zeile mit 3 Spalten aus
Expr1008 Expr1009 Expr1007
----------- ----------- -----------
NULL 1048576 10
Der Verkettungsoperator verbindet diese 2 Zeilen und gibt die 3 Spalten aus, aber sie werden jetzt umbenannt
Expr1010 Expr1011 Expr1012
----------- ----------- -----------
NULL NULL 60
NULL 1048576 10
Die Expr1012
Spalte besteht aus einer Reihe von Flags, die intern verwendet werden, um bestimmte Sucheigenschaften für die Storage Engine zu definieren .
Der nächste Berechnungsskalar entlang gibt 2 Zeilen aus
Expr1010 Expr1011 Expr1012 Expr1013 Expr1014 Expr1015
----------- ----------- ----------- ----------- ----------- -----------
NULL NULL 60 True 4 16
NULL 1048576 10 False 0 0
Die letzten drei Spalten sind wie folgt definiert und werden nur zu Sortierzwecken verwendet, bevor sie dem Operator "Zusammenführungsintervall" vorgelegt werden
[Expr1013] = Scalar Operator(((4)&[Expr1012]) = (4) AND NULL = [Expr1010]),
[Expr1014] = Scalar Operator((4)&[Expr1012]),
[Expr1015] = Scalar Operator((16)&[Expr1012])
Expr1014
und Expr1015
testen Sie einfach, ob bestimmte Bits im Flag aktiviert sind.
Expr1013
erscheint für beide eine boolean Spalte true , wenn das Bit zurück 4
auf und Expr1010
ist NULL
.
Wenn ich andere Vergleichsoperatoren in der Abfrage ausprobiere, erhalte ich diese Ergebnisse
+----------+----------+----------+-------------+----+----+---+---+---+---+
| Operator | Expr1010 | Expr1011 | Flags (Dec) | Flags (Bin) |
| | | | | 32 | 16 | 8 | 4 | 2 | 1 |
+----------+----------+----------+-------------+----+----+---+---+---+---+
| > | 1048576 | NULL | 6 | 0 | 0 | 0 | 1 | 1 | 0 |
| >= | 1048576 | NULL | 22 | 0 | 1 | 0 | 1 | 1 | 0 |
| <= | NULL | 1048576 | 42 | 1 | 0 | 1 | 0 | 1 | 0 |
| < | NULL | 1048576 | 10 | 0 | 0 | 1 | 0 | 1 | 0 |
| = | 1048576 | 1048576 | 62 | 1 | 1 | 1 | 1 | 1 | 0 |
| IS NULL | NULL | NULL | 60 | 1 | 1 | 1 | 1 | 0 | 0 |
+----------+----------+----------+-------------+----+----+---+---+---+---+
Daraus schließe ich, dass Bit 4 "Bereichsanfang" bedeutet (im Gegensatz zu "unbegrenzt") und Bit 16 bedeutet, dass der Bereichsanfang inklusive ist.
Diese 6-Spalten-Ergebnismenge wird vom SORT
Operator sortiert nach ausgegeben
Expr1013 DESC, Expr1014 ASC, Expr1010 ASC, Expr1015 DESC
. Unter der Annahme , True
dargestellt durch 1
und False
durch 0
die zuvor dargestellten resultset ist bereits in dieser Reihenfolge.
Basierend auf meinen vorherigen Annahmen besteht der Nettoeffekt dieser Art darin, die Bereiche für das Zusammenführungsintervall in der folgenden Reihenfolge darzustellen
ORDER BY
HasStartOfRangeAndItIsNullFirst,
HasUnboundedStartOfRangeFirst,
StartOfRange,
StartOfRangeIsInclusiveFirst
Der Operator für das Zusammenführungsintervall gibt 2 Zeilen aus
Expr1010 Expr1011 Expr1012
----------- ----------- -----------
NULL NULL 60
NULL 1048576 10
Für jede ausgegebene Zeile wird eine Bereichssuche durchgeführt
Seek Keys[1]: Start:[dbo].[t].c2 > Scalar Operator([Expr1010]),
End: [dbo].[t].c2 < Scalar Operator([Expr1011])
Es sieht also so aus, als würden zwei Suchvorgänge ausgeführt. Eins anscheinend > NULL AND < NULL
und eins > NULL AND < 1048576
. Allerdings sind die Fahnen , die in scheinen dies zu ändern , übergeben bekommen IS NULL
und < 1048576
jeweils. Hoffentlich kann @sqlkiwi dies klären und eventuelle Ungenauigkeiten korrigieren!
Wenn Sie die Abfrage leicht in ändern
select *
from t
where
c2 > 1048576
or c2 = 0
;
Dann sieht der Plan mit einer Indexsuche mit mehreren Suchprädikaten viel einfacher aus.
Der Plan zeigt Seek Keys
Start: c2 >= 0, End: c2 <= 0,
Start: c2 > 1048576
Die Erklärung, warum dieser einfachere Plan für den Fall im OP nicht verwendet werden kann, wird von SQLKiwi in den Kommentaren zum zuvor verlinkten Blog-Beitrag gegeben .
Eine Indexsuche mit mehreren Prädikaten kann nicht verschiedene Arten von Vergleichsprädikaten (dh Is
und Eq
im Fall des OP) mischen . Dies ist nur eine aktuelle Einschränkung des Produkts (und vermutlich der Grund, warum der Gleichheitstest in der letzten Abfrage c2 = 0
unter Verwendung von implementiert wird >=
und <=
nicht nur die einfache Gleichheitssuche, die Sie für die Abfrage erhalten c2 = 0 OR c2 = 1048576
.
62
ist für einen Gleichstellungsvergleich. Ich denke, das60
muss bedeuten, dass anstatt> AND <
wie im Plan gezeigt, Sie tatsächlich erhalten, es>= AND <=
sei denn, es ist ein explizitesIS NULL
Flag, vielleicht (?) Oder vielleicht zeigt das Bit2
etwas anderes an, das nichts damit zu60
tun hat,set ansi_nulls off
und ist immer noch gleich, als wenn ich es ändere undc2 = null
es bleibt dabei60
Die konstanten Scans sind eine Möglichkeit für SQL Server, einen Bucket zu erstellen, in den etwas später im Ausführungsplan eingefügt wird. Ich habe hier eine ausführlichere Erklärung dazu veröffentlicht . Um zu verstehen, wofür der ständige Scan gedacht ist, müssen Sie sich den Plan genauer ansehen. In diesem Fall werden die Compute Scalar-Operatoren verwendet, um den durch den konstanten Scan erstellten Speicherplatz aufzufüllen.
Die Compute Scalar-Operatoren werden mit NULL und dem Wert 1045876 geladen, daher werden sie eindeutig mit dem Loop Join verwendet, um die Daten zu filtern.
Der wirklich coole Teil ist, dass dieser Plan Trivial ist. Dies bedeutet, dass ein minimaler Optimierungsprozess durchgeführt wurde. Alle Vorgänge führen zum Zusammenführungsintervall. Dies wird verwendet, um einen minimalen Satz von Vergleichsoperatoren für eine Indexsuche zu erstellen ( Details dazu hier ).
Die ganze Idee ist, überlappende Werte loszuwerden, damit die Daten dann mit minimalen Durchläufen herausgezogen werden können. Obwohl es sich immer noch um eine Schleifenoperation handelt, werden Sie feststellen, dass die Schleife genau einmal ausgeführt wird, was bedeutet, dass es sich tatsächlich um einen Scan handelt.
ADDENDUM: Dieser letzte Satz ist aus. Es gab zwei Suchanfragen. Ich habe den Plan falsch verstanden. Der Rest der Konzepte ist das gleiche und das Ziel, minimale Pässe, ist das gleiche.
quelle