Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Desempenho de INNER JOIN vs LEFT JOIN no SQL Server


Um LEFT JOIN absolutamente não é mais rápido que um INNER JOIN . Na verdade, é mais lento; por definição, uma junção externa (LEFT JOIN ou RIGHT JOIN ) tem que fazer todo o trabalho de um INNER JOIN mais o trabalho extra de extensão nula dos resultados. Também seria esperado retornar mais linhas, aumentando ainda mais o tempo total de execução simplesmente devido ao tamanho maior do conjunto de resultados.

(E mesmo se um LEFT JOIN foram mais rápido em específicos situações devido a alguma confluência de fatores difícil de imaginar, não é funcionalmente equivalente a um INNER JOIN , então você não pode simplesmente substituir todas as instâncias de uma pela outra!)

Muito provavelmente seus problemas de desempenho estão em outro lugar, como não ter uma chave candidata ou chave estrangeira indexada corretamente. 9 mesas é muito para se juntar, então a desaceleração pode literalmente estar em quase qualquer lugar. Se você postar seu esquema, poderemos fornecer mais detalhes.

Editar:

Refletindo mais sobre isso, eu poderia pensar em uma circunstância em que um LEFT JOIN pode ser mais rápido que um INNER JOIN , e é quando:
  • Algumas das tabelas são muito pequeno (digamos, menos de 10 linhas);
  • As tabelas não têm índices suficientes para cobrir a consulta.

Considere este exemplo:
CREATE TABLE #Test1
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test1 (ID, Name) VALUES (1, 'One')
INSERT #Test1 (ID, Name) VALUES (2, 'Two')
INSERT #Test1 (ID, Name) VALUES (3, 'Three')
INSERT #Test1 (ID, Name) VALUES (4, 'Four')
INSERT #Test1 (ID, Name) VALUES (5, 'Five')

CREATE TABLE #Test2
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test2 (ID, Name) VALUES (1, 'One')
INSERT #Test2 (ID, Name) VALUES (2, 'Two')
INSERT #Test2 (ID, Name) VALUES (3, 'Three')
INSERT #Test2 (ID, Name) VALUES (4, 'Four')
INSERT #Test2 (ID, Name) VALUES (5, 'Five')

SELECT *
FROM #Test1 t1
INNER JOIN #Test2 t2
ON t2.Name = t1.Name

SELECT *
FROM #Test1 t1
LEFT JOIN #Test2 t2
ON t2.Name = t1.Name

DROP TABLE #Test1
DROP TABLE #Test2

Se você executar isso e visualizar o plano de execução, verá que o INNER JOIN consulta realmente custa mais do que o LEFT JOIN , porque satisfaz os dois critérios acima. É porque o SQL Server quer fazer uma correspondência de hash para o INNER JOIN , mas faz loops aninhados para o LEFT JOIN; o primeiro é normalmente muito mais rápido, mas como o número de linhas é tão pequeno e não há índice para usar, a operação de hash acaba sendo a parte mais cara da consulta.

Você pode ver o mesmo efeito escrevendo um programa em sua linguagem de programação favorita para realizar um grande número de pesquisas em uma lista com 5 elementos, versus uma tabela de hash com 5 elementos. Por causa do tamanho, a versão da tabela de hash é realmente mais lenta. Mas aumente para 50 elementos, ou 5.000 elementos, e a versão da lista fica lenta, porque é O(N) vs. O(1) para a tabela de hash.

Mas altere esta consulta para o ID coluna em vez de Name e você verá uma história muito diferente. Nesse caso, ele faz loops aninhados para ambas as consultas, mas o INNER JOIN version é capaz de substituir uma das varreduras de índice clusterizado por uma busca - o que significa que isso será literalmente uma ordem de magnitude mais rápido com um grande número de linhas.

Então a conclusão é mais ou menos o que eu mencionei vários parágrafos acima; isso é quase certamente um problema de indexação ou cobertura de índice, possivelmente combinado com uma ou mais tabelas muito pequenas. Essas são as únicas circunstâncias em que o SQL Server pode às vezes escolha um plano de execução pior para um INNER JOIN do que um LEFT JOIN .