Desempenho SQL em LEFT OUTER JOIN vs NOT EXISTS

Se eu quiser encontrar um conjunto de inputs na tabela A, mas não na tabela B, posso usar LEFT OUTER JOIN ou NOT EXISTS. Ouvi dizer que o SQL Server é voltado para o ANSI e, em alguns casos, o LEFT OUTER JOINs é muito mais eficiente do que o NOT EXISTS. O ANSI JOIN terá um desempenho melhor neste caso? e são operadores de junit mais eficientes que NOT EXISTS em geral no SQL Server?

O link de Joe é um bom ponto de partida. Quassnoi também cobre isso.

Em geral, se os campos estiverem indexados corretamente OU se você desejar filtrar mais registros (ou seja, ter muitas linhas EXIST na subconsulta) NOT EXISTS terá um desempenho melhor.

EXISTS e NOT EXISTS ambos curto-circuito – assim que um registro coincide com o critério, ele é incluído ou filtrado e o otimizador passa para o próximo registro.

LEFT JOIN unirá TODOS OS REGISTROS, independentemente de eles corresponderem ou não, e filtrará todos os registros não correspondentes. Se suas tabelas forem grandes e / ou você tiver vários critérios de JOIN , isso pode ser muito intensivo em resources.

Eu normalmente tento usar NOT EXISTS e EXISTS que possível. Para o SQL Server, IN e NOT IN são semanticamente equivalentes e podem ser mais fáceis de escrever. Esses são os únicos operadores que você encontrará no SQL Server com garantia de curto-circuito.

A melhor discussão que li sobre esse tópico para o SQL Server está aqui .

Pessoalmente, acho que esse aqui é um grande e velho, “Depende”. Eu vi casos em que cada método superou o outro.

Sua melhor aposta é testar os dois e ver qual apresenta melhor desempenho. Se é uma situação em que as tabelas serão sempre pequenas e o desempenho não é tão crucial, então eu vou apenas com o que for mais claro para você (geralmente NOT EXISTS para a maioria das pessoas) e siga em frente.

Esta input de blog dá exemplos de várias maneiras ( NÃO IN , EXPLOSÃO EXTERNA , REINAÇÃO EXTERNA ESQUERDA , EXCETO e NÃO EXISTE ) para obter os mesmos resultados e provar que Não existe (Anti-associação esquerda) é a melhor opção em cache frio e cache quente cenários.

Eu tenho me perguntado como podemos usar o índice na tabela que estamos excluindo nestes casos que o OP descreve.

Diga que temos:

  table EMPLOYEE (emp_id int, name varchar) and table EMPLOYEE_LOCATION (emp_id int, loc_id int) 

No meu exemplo do mundo real, minhas tabelas são muito mais largas e contêm 1 milhão + linhas, simplifiquei o esquema por exemplo.

Se eu quiser excluir as linhas de EMPLOYEE_LOCATION que não têm emp_id’s correspondentes no EMPLOYEE, obviamente posso usar a técnica externa Esquerda ou NOT IN, mas estava me perguntando …

Se ambas as tabelas tiverem índices com a coluna principal de emp_id, valeria a pena tentar usá-las?

Talvez eu pudesse extrair o emp_id do EMPLOYEE, o emp_id de EMPLOYEE_LOCATION para uma tabela temporária e obter o emp_id das tabelas temporárias que desejo excluir.

Eu poderia então circular em torno destes emp_id e realmente usar o índice da seguinte forma:

 loop for each emp_id X to delete -- (this would be a cursor) DELETE EMPLOYEE_LOCATION WHERE emp_id = X 

Eu sei que há sobrecarga com o cursor, mas no meu exemplo real estou lidando com tabelas enormes, então eu acho que explicitamente usando o índice é desejável.

Respondido on dba.stackexchange

Uma exceção que notei para os NOT EXISTS sendo superior (embora marginalmente) para LEFT JOIN ... WHERE IS NULL ao usar Servidores Vinculados .

Ao examinar os planos de execução, parece que o operador NOT EXISTS é executado de maneira aninhada em loop. Por que é executado em uma base por linha (o que eu suponho faz sentido).

Exemplo de plano de execução demonstrando esse comportamento: insira a descrição da imagem aqui