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
.