Tenho uma consulta T-SQL semelhante a esta (um pouco mais complexa, simplificando aqui):
SELECT *
FROM ParticipantTable p
WHERE p.OrganizationId = @p__linq__0
AND p.ParticipantId IN (
@p__linq__1,
@p__linq__2,
@p__linq__3,
@p__linq__4,
@p__linq__5,
@p__linq__6,
@p__linq__7,
@p__linq__8,
@p__linq__9,
@p__linq__10
)
Isso resulta em um plano de consulta semelhante a este aqui (recortado na parte relevante):
Fiquei surpreso com o Clustered Index Seek realizando uma comparação maior que/menor que em vez de uma pesquisa "normal" por valor de chave de entrada:
Seek Keys[1]: Prefix: [snip].OrganizationId = Scalar Operator([@p__linq__0]); Start: [snip].ParticipantId > Scalar Operator([Expr1031]); End: [snip].ParticipantId < Scalar Operator([Expr1032])
Por que isso? Buscar um intervalo em não é uniqueidentifier
realmente ineficiente, resultando facilmente na seleção de um intervalo muito amplo de valores? Não seria muito mais eficiente fazer um loop nos valores de entrada e buscar um por um? Ou, com apenas dez valores, puxar os valores diretamente para o operador seek?
Imagino que isso possa ser apenas uma otimização porque a organização em questão tem um número baixo de participantes, mas não seria mais sensato extrair os valores para o operador de busca?
Além disso, apenas por interesse acadêmico, há uma maneira de forçar o SQL Server a buscar nos valores em vez do intervalo? WITH (FORCESEEK([snip](OrganizationId, ParticipantId))
não funciona, ele ainda buscará com maior que/menor que. Eu também adicionei OPTIMIZE FOR UNKNOWN
, mas realmente não esperava que fizesse nada aqui (e não fez).
É isso que ele está realmente fazendo. O
>
and<
mostrado no plano de execução é um pouco enganoso e um artefato do mecanismo subjacente sendo uma funcionalidade genérica usada para múltiplos casos.Ele usa o mecanismo de busca dinâmica e passa um sinalizador
62
que informa ao mecanismo de armazenamento para fazer uma busca de igualdade.(ou seja, todos os cinco bits dos valores de 2 a 32, inclusive, são definidos de acordo com o link anterior e a tabela na minha resposta aqui )
Você verá isso
62
ao observar as propriedades dos escalares de computação entre os operadores de concatenação e varredura constante.Ele é empregado aqui para deduzir a lista parametrizada e então fazer uma busca para cada valor que permanece (pois seria um erro retornar a mesma linha mais de uma vez se ela estivesse na
IN
lista mais de uma vez)Para mais informações sobre esse padrão de plano de execução, consulte Buscas dinâmicas e conversões implícitas ocultas