As varreduras constantes produzem uma única linha na memória sem colunas. O escalar de computação superior gera uma única linha com 3 colunas
Expr1005 Expr1006 Expr1004
----------- ----------- -----------
NULL NULL 60
O escalar de computação inferior gera uma única linha com 3 colunas
Expr1008 Expr1009 Expr1007
----------- ----------- -----------
NULL 1048576 10
O operador de concatenação Une essas 2 linhas e gera as 3 colunas, mas agora elas são renomeadas
Expr1010 Expr1011 Expr1012
----------- ----------- -----------
NULL NULL 60
NULL 1048576 10
A Expr1012
coluna é um conjunto de sinalizadores usados internamente para definir determinadas propriedades de pesquisa para o Mecanismo de Armazenamento .
O próximo escalar de computação ao longo de duas linhas de saída
Expr1010 Expr1011 Expr1012 Expr1013 Expr1014 Expr1015
----------- ----------- ----------- ----------- ----------- -----------
NULL NULL 60 True 4 16
NULL 1048576 10 False 0 0
As últimas três colunas são definidas da seguinte forma e são usadas apenas para fins de classificação antes de serem apresentadas ao Operador de Intervalo de Mesclagem
[Expr1013] = Scalar Operator(((4)&[Expr1012]) = (4) AND NULL = [Expr1010]),
[Expr1014] = Scalar Operator((4)&[Expr1012]),
[Expr1015] = Scalar Operator((16)&[Expr1012])
Expr1014
e Expr1015
apenas teste se certos bits estão ativados na bandeira.
Expr1013
parece retornar uma coluna booleana true se o bit for 4
estiver ativado e Expr1010
is NULL
.
Ao tentar outros operadores de comparação na consulta, obtenho esses 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 |
+----------+----------+----------+-------------+----+----+---+---+---+---+
Pelo qual deduzo que o Bit 4 significa "Tem início do intervalo" (em vez de não ter limites) e o Bit 16 significa que o início do intervalo é inclusivo.
Este conjunto de resultados de 6 colunas é emitido pelo SORT
operador classificado por
Expr1013 DESC, Expr1014 ASC, Expr1010 ASC, Expr1015 DESC
. Assumir que True
é representado por 1
e False
pelo 0
conjunto de resultados representado anteriormente já está nessa ordem.
Com base em minhas suposições anteriores, o efeito líquido desse tipo é apresentar os intervalos no intervalo de mesclagem na seguinte ordem
ORDER BY
HasStartOfRangeAndItIsNullFirst,
HasUnboundedStartOfRangeFirst,
StartOfRange,
StartOfRangeIsInclusiveFirst
O operador de intervalo de mesclagem gera 2 linhas
Expr1010 Expr1011 Expr1012
----------- ----------- -----------
NULL NULL 60
NULL 1048576 10
Para cada linha emitida, é realizada uma busca por intervalo
Seek Keys[1]: Start:[dbo].[t].c2 > Scalar Operator([Expr1010]),
End: [dbo].[t].c2 < Scalar Operator([Expr1011])
Portanto, parece que duas buscas são realizadas. Um aparentemente > NULL AND < NULL
e um > NULL AND < 1048576
. No entanto, os sinalizadores passados parecem modificar isso para IS NULL
e < 1048576
respectivamente. Espero que o @sqlkiwi possa esclarecer isso e corrigir quaisquer imprecisões!
Se você alterar a consulta ligeiramente para
select *
from t
where
c2 > 1048576
or c2 = 0
;
Em seguida, o plano parece muito mais simples com uma pesquisa de índice com vários predicados de pesquisa.
O plano mostra Seek Keys
Start: c2 >= 0, End: c2 <= 0,
Start: c2 > 1048576
A explicação do motivo pelo qual esse plano mais simples não pode ser usado para o caso no OP é fornecida pelo SQLKiwi nos comentários da postagem do blog vinculada anteriormente .
Uma busca de índice com vários predicados não pode misturar diferentes tipos de predicados de comparação (por exemplo, Is
e Eq
no caso do OP). Essa é apenas uma limitação atual do produto (e é presumivelmente a razão pela qual o teste de igualdade na última consulta c2 = 0
é implementado usando >=
e <=
não apenas a igualdade direta que você procura para a consulta c2 = 0 OR c2 = 1048576
.