Los escaneos constantes producen cada uno una fila en memoria sin columnas. El escalar de cómputo superior genera una sola fila con 3 columnas
Expr1005 Expr1006 Expr1004
----------- ----------- -----------
NULL NULL 60
El escalar de proceso inferior genera una sola fila con 3 columnas
Expr1008 Expr1009 Expr1007
----------- ----------- -----------
NULL 1048576 10
El operador de concatenación une estas 2 filas y genera las 3 columnas, pero ahora se renombra
Expr1010 Expr1011 Expr1012
----------- ----------- -----------
NULL NULL 60
NULL 1048576 10
La Expr1012columna es un conjunto de indicadores utilizados internamente para definir ciertas propiedades de búsqueda para Storage Engine .
El siguiente cálculo escalar a lo largo de las salidas 2 filas
Expr1010 Expr1011 Expr1012 Expr1013 Expr1014 Expr1015
----------- ----------- ----------- ----------- ----------- -----------
NULL NULL 60 True 4 16
NULL 1048576 10 False 0 0
Las últimas tres columnas se definen de la siguiente manera y solo se usan para fines de clasificación antes de presentarlas al Operador del intervalo de fusión
[Expr1013] = Scalar Operator(((4)&[Expr1012]) = (4) AND NULL = [Expr1010]),
[Expr1014] = Scalar Operator((4)&[Expr1012]),
[Expr1015] = Scalar Operator((16)&[Expr1012])
Expr1014y Expr1015solo pruebe si ciertos bits están activados en la bandera.
Expr1013parece devolver una columna booleana verdadera si tanto el bit for 4está activado como si Expr1010está NULLactivado
Al probar otros operadores de comparación en la consulta obtengo estos resultados
+----------+----------+----------+-------------+----+----+---+---+---+---+
| 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 |
+----------+----------+----------+-------------+----+----+---+---+---+---+
De lo cual deduzco que el Bit 4 significa "Tiene inicio de rango" (en lugar de no estar limitado) y el Bit 16 significa que el inicio del rango es inclusivo.
Este conjunto de resultados de 6 columnas se emite desde el SORToperador ordenado por
Expr1013 DESC, Expr1014 ASC, Expr1010 ASC, Expr1015 DESC. Asumir que Trueestá representado por 1y Falsepor 0el conjunto de resultados representado anteriormente ya está en ese orden.
Según mis supuestos anteriores, el efecto neto de este tipo es presentar los rangos al intervalo de fusión en el siguiente orden
ORDER BY
HasStartOfRangeAndItIsNullFirst,
HasUnboundedStartOfRangeFirst,
StartOfRange,
StartOfRangeIsInclusiveFirst
El operador de intervalo de fusión genera 2 filas
Expr1010 Expr1011 Expr1012
----------- ----------- -----------
NULL NULL 60
NULL 1048576 10
Para cada fila emitida se realiza una búsqueda de rango
Seek Keys[1]: Start:[dbo].[t].c2 > Scalar Operator([Expr1010]),
End: [dbo].[t].c2 < Scalar Operator([Expr1011])
Entonces parecería que se realizan dos búsquedas. Uno aparentemente > NULL AND < NULLy uno > NULL AND < 1048576. Sin embargo, las banderas que se pasan parecen modificar esto IS NULLy < 1048576respectivamente. ¡Ojalá @sqlkiwi pueda aclarar esto y corregir cualquier inexactitud!
Si cambia la consulta ligeramente a
select *
from t
where
c2 > 1048576
or c2 = 0
;
Entonces el plan se ve mucho más simple con una búsqueda de índice con múltiples predicados de búsqueda.
El plan muestra Seek Keys
Start: c2 >= 0, End: c2 <= 0,
Start: c2 > 1048576
SQLKiwi da la explicación de por qué este plan más simple no puede usarse para el caso en el OP en los comentarios a la publicación de blog vinculada anteriormente .
Una búsqueda de índice con múltiples predicados no puede mezclar diferentes tipos de predicados de comparación (es decir, Isy Eqen el caso del OP). Esta es solo una limitación actual del producto (y es presumiblemente la razón por la cual c2 = 0se implementa la prueba de igualdad en la última consulta >=y <=no solo la búsqueda de igualdad directa que obtiene para la consulta c2 = 0 OR c2 = 1048576.