Les analyses constantes produisent chacune une seule ligne en mémoire sans colonnes. Le scalaire de calcul supérieur génère une seule ligne avec 3 colonnes
Expr1005 Expr1006 Expr1004
----------- ----------- -----------
NULL NULL 60
Le scalaire inférieur calcule une seule ligne avec 3 colonnes
Expr1008 Expr1009 Expr1007
----------- ----------- -----------
NULL 1048576 10
L'opérateur de concaténation Rassemble ces 2 lignes et affiche les 3 colonnes mais elles sont maintenant renommées
Expr1010 Expr1011 Expr1012
----------- ----------- -----------
NULL NULL 60
NULL 1048576 10
La Expr1012
colonne est un ensemble d'indicateurs utilisés en interne pour définir certaines propriétés de recherche pour le moteur de stockage .
Le prochain calcul scalaire produit 2 lignes
Expr1010 Expr1011 Expr1012 Expr1013 Expr1014 Expr1015
----------- ----------- ----------- ----------- ----------- -----------
NULL NULL 60 True 4 16
NULL 1048576 10 False 0 0
Les trois dernières colonnes sont définies comme suit et sont juste utilisées à des fins de tri avant d'être présentées à l'opérateur d'intervalle de fusion
[Expr1013] = Scalar Operator(((4)&[Expr1012]) = (4) AND NULL = [Expr1010]),
[Expr1014] = Scalar Operator((4)&[Expr1012]),
[Expr1015] = Scalar Operator((16)&[Expr1012])
Expr1014
et Expr1015
juste tester si certains bits sont activés dans le drapeau.
Expr1013
semble renvoyer une colonne booléenne true si le bit for 4
est allumé et l' Expr1010
est NULL
.
En essayant d'autres opérateurs de comparaison dans la requête, j'obtiens ces résultats
+----------+----------+----------+-------------+----+----+---+---+---+---+
| 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 |
+----------+----------+----------+-------------+----+----+---+---+---+---+
D'où je déduis que le bit 4 signifie "a le début de la plage" (par opposition à non illimité) et le bit 16 signifie que le début de la plage est inclusif.
Ce jeu de résultats à 6 colonnes est émis par l' SORT
opérateur trié par
Expr1013 DESC, Expr1014 ASC, Expr1010 ASC, Expr1015 DESC
. En supposant True
est représenté par 1
et False
par 0
le jeu de résultats précédemment représenté est déjà dans cet ordre.
Sur la base de mes hypothèses précédentes, l'effet net de ce type est de présenter les plages à l'intervalle de fusion dans l'ordre suivant
ORDER BY
HasStartOfRangeAndItIsNullFirst,
HasUnboundedStartOfRangeFirst,
StartOfRange,
StartOfRangeIsInclusiveFirst
L'opérateur d'intervalle de fusion génère 2 lignes
Expr1010 Expr1011 Expr1012
----------- ----------- -----------
NULL NULL 60
NULL 1048576 10
Pour chaque ligne émise, une recherche de plage est effectuée
Seek Keys[1]: Start:[dbo].[t].c2 > Scalar Operator([Expr1010]),
End: [dbo].[t].c2 < Scalar Operator([Expr1011])
Il semblerait donc que deux recherches soient effectuées. Un apparemment > NULL AND < NULL
et un > NULL AND < 1048576
. Cependant, les drapeaux transmis semblent modifier cela respectivement IS NULL
et < 1048576
. Espérons que @sqlkiwi puisse clarifier cela et corriger toute inexactitude!
Si vous modifiez légèrement la requête en
select *
from t
where
c2 > 1048576
or c2 = 0
;
Ensuite, le plan semble beaucoup plus simple avec une recherche d'index avec plusieurs prédicats de recherche.
Le plan montre Seek Keys
Start: c2 >= 0, End: c2 <= 0,
Start: c2 > 1048576
L'explication pour laquelle ce plan plus simple ne peut pas être utilisé pour le cas dans l'OP est donnée par SQLKiwi dans les commentaires de l' article de blog lié précédent .
Une recherche d'index avec plusieurs prédicats ne peut pas mélanger différents types de prédicat de comparaison (c'est-à-dire Is
et Eq
dans le cas de l'OP). Il s'agit simplement d'une limitation actuelle du produit (et c'est probablement la raison pour laquelle le test d'égalité dans la dernière requête c2 = 0
est implémenté en utilisant >=
et <=
non pas simplement la recherche d'égalité simple que vous obtenez pour la requête c2 = 0 OR c2 = 1048576
.