Qual é o algoritmo interno de como o operador Except funciona nos bastidores do SQL Server? Será necessário internamente um hash de cada linha e comparar?
David Lozinksi realizou um estudo, SQL: A maneira mais rápida de inserir novos registros onde um ainda não existe. Ele mostrou que a instrução Except é a mais rápida para grandes linhas de número; intimamente ligada aos nossos resultados abaixo.
Suposição: Eu acho que a junção à esquerda seria mais rápida, pois compara apenas 1 coluna, exceto que levaria mais tempo, pois precisa comparar todas as colunas.
Com esses resultados, agora nosso pensamento é Exceto automática e internamente, um hash de cada linha? Eu olhei para o plano de execução Exceto e ele utiliza algum hash.
Histórico: Nossa equipe estava comparando duas tabelas de heap. Tabela A Linhas que não estão na Tabela B, foram inseridas na Tabela B.
As tabelas de heap (do sistema de arquivos de texto herdado) não possuem chaves / guias / identificadores primários. Algumas das tabelas tinham linhas duplicadas; portanto, encontramos o Hash de cada linha, removemos duplicatas e criamos identificadores de chave primária.
1) Primeiro, executamos uma instrução exceto, excluindo (coluna de hash)
select * from TableA
Except
Select * from TableB,
2) Em seguida, fizemos uma comparação de junção esquerda entre as duas tabelas no HashRowId
select *
FROM dbo.TableA A
left join dbo.TableB B
on A.RowHash = B.RowHash
where B.Hash is null
surpreendentemente, o Except Statement Insert foi o mais rápido.
Na verdade, os resultados são mapeados perto dos resultados dos testes de David Lozinksi
fonte
Respostas:
Eu não diria que existe um algoritmo interno especial para
EXCEPT
. ParaA EXCEPT B
, o mecanismo pega tuplas distintas (se necessário) de A e subtrai linhas que correspondem a B. Não há operadores de plano de consulta especiais. O distinto e a subtração são implementados através dos operadores típicos que você veria com uma classificação ou com uma junção. Junção de loop aninhada, junção de mesclagem e junção de hash são todas suportadas. Para mostrar isso, jogarei 15 milhões de linhas em um par de pilhas:O otimizador toma decisões habituais baseadas em custos sobre como implementar a classificação e a junção. Com dois montões, recebo uma junção de hash conforme o esperado. Você pode ver outros tipos de junção naturalmente adicionando índices ou alterando os dados em qualquer tabela. Abaixo forço a junção de mesclagem e loop com dicas apenas para fins ilustrativos:
Não. Ele é implementado como qualquer outra junção. Uma diferença é que os NULLs são tratados como iguais. Este é um tipo especial de comparação que você pode ver no plano de execução:
<Compare CompareOp="IS">
. No entanto, você pode obter o mesmo plano com o T-SQL que não inclui aEXCEPT
palavra - chave. Por exemplo, o seguinte tem exatamente o mesmo plano deEXCEPT
consulta que a consulta que usa uma junção de hash:A difusão do XML dos planos de execução apenas revela diferenças superficiais em torno de aliases e coisas assim. Os resíduos da sonda para as junções de hash fazem a comparação de linhas. Eles são os mesmos para as duas consultas:
Se você ainda tiver dúvidas, executei o PerfView com a maior taxa de amostragem disponível para obter pilhas de chamadas para a consulta
EXCEPT
e a consulta sem ela. Aqui estão os resultados lado a lado:Não há diferença real. As pilhas de chamadas nesse hash de referência estão presentes devido às correspondências de hash no plano. Se eu adicionar índices para obter uma junção de mesclagem natural, você não verá nenhuma referência ao hash nas pilhas de chamadas:
Qualquer hash que ocorre é devido à implementação de operadores de correspondência de hash. Não há nada de especial sobre o
EXCEPT
que leva a uma comparação interna de hash especial.fonte