Observando a execução de consultas com estatísticas de consulta ao vivo, notei que parece que o SQL Server está construindo preguiçosamente uma tabela de hash a partir da entrada de compilação de uma junção de hash.
Esta é uma diferença significativa no caso de 0 linhas de sondagem. Ele potencialmente salva toda a árvore do lado da compilação.
Eu sempre pensei que um hash funcionasse assim:
- Crie uma tabela de hash do lado da compilação.
- Combine todas as linhas do probe com ele.
Mas é o seguinte?
- Puxe a primeira linha de sonda.
- Conclua a operação se nenhuma linha estiver disponível (curto-circuito).
- Combine todas as linhas do probe com ele.
Não tenho certeza de como testar conclusivamente de que maneira é. Não tenho certeza se a saída das Estatísticas de consulta ao vivo pode ser confiável dessa maneira. Alguém sabe como isto funciona?
Se você postar o plano de consulta real para sua consulta específica, poderemos comentar sobre isso mais diretamente.
Mas, em geral, acredito (e sempre observei) que o operador hash join sempre é executado como você esperava:
Isso geralmente faz sentido, pois o SQL Server colocará o conjunto de linhas menor (estimado) no lado de compilação da junção. Espera-se que o lado do probe seja maior que o lado da compilação (e, portanto, contenha pelo menos algumas linhas).
Além disso, o SQL Server tem uma potencial otimização de bitmap que pode ser aplicada ao lado de investigação de uma junção de hash em alguns casos, mas essa otimização requer que o lado de compilação seja processado primeiro.
Um exemplo
Para uma consulta simples em que forçamos um lado de compilação grande da junção de hash e um lado de teste vazio, o plano de execução real mostra que todas as linhas são processadas no lado de compilação da junção.
O lado de construção pode ser ignorado?
Há pelo menos um exemplo em que o lado de construção da junção de hash pode ser ignorado: Em alguns casos, a junção inteira pode ser eliminada. Por exemplo, aqui o SQL Server é capaz de provar antes da execução que o lado do probe terá 0 linhas. O plano de consulta final é, portanto, uma varredura constante e não há junção de hash.
E o modo de lote?
Com base em um teste rápido, parece que o operador de junção de hash do modo de lote também processará totalmente o lado de compilação da junção de hash.