Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Performances INNER JOIN vs LEFT JOIN dans SQL Server

Une LEFT JOIN n'est absolument pas plus rapide qu'un INNER JOIN . En fait, c'est plus lent; par définition, une jointure externe (LEFT JOIN ou RIGHT JOIN ) doit faire tout le travail d'un INNER JOIN plus le travail supplémentaire d'extension nulle des résultats. On s'attendrait également à ce qu'il renvoie plus de lignes, augmentant encore le temps d'exécution total simplement en raison de la plus grande taille de l'ensemble de résultats.

(Et même si un LEFT JOIN étaient plus rapide dans spécifique situations dues à une confluence difficile à imaginer de facteurs, il n'est pas fonctionnellement équivalent à un INNER JOIN , vous ne pouvez donc pas simplement remplacer toutes les instances de l'une par l'autre !)

Il est fort probable que vos problèmes de performances se situent ailleurs, comme le fait de ne pas avoir correctement indexé une clé candidate ou une clé étrangère. 9 tables, c'est beaucoup à rejoindre, donc le ralentissement pourrait littéralement être presque n'importe où. Si vous publiez votre schéma, nous pourrons peut-être vous fournir plus de détails.

Modifier :

En réfléchissant davantage à cela, je pourrais penser à une circonstance dans laquelle un LEFT JOIN peut être plus rapide qu'un INNER JOIN , et c'est alors :

  • Certaines tables sont très petit (par exemple, moins de 10 lignes) ;
  • Les tables n'ont pas suffisamment d'index pour couvrir la requête.

Prenons cet exemple :

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

Si vous exécutez ceci et affichez le plan d'exécution, vous verrez que le INNER JOIN la requête coûte en effet plus cher que le LEFT JOIN , car il satisfait aux deux critères ci-dessus. C'est parce que SQL Server veut faire une correspondance de hachage pour le INNER JOIN , mais fait des boucles imbriquées pour le LEFT JOIN; le premier est normalement beaucoup plus rapide, mais puisque le nombre de lignes est si petit et s'il n'y a pas d'index à utiliser, l'opération de hachage s'avère être la partie la plus coûteuse de la requête.

Vous pouvez voir le même effet en écrivant un programme dans votre langage de programmation préféré pour effectuer un grand nombre de recherches sur une liste avec 5 éléments, par rapport à une table de hachage avec 5 éléments. En raison de la taille, la version de la table de hachage est en fait plus lente. Mais augmentez-le à 50 éléments, ou 5 000 éléments, et la version de la liste ralentit, car elle est O(N) contre O(1) pour la table de hachage.

Mais changez cette requête pour qu'elle soit sur l'ID colonne au lieu de Name et vous verrez une histoire très différente. Dans ce cas, il fait des boucles imbriquées pour les deux requêtes, mais le INNER JOIN version est capable de remplacer l'un des balayages d'index groupés par une recherche - ce qui signifie que ce sera littéralement un ordre de grandeur plus rapide avec un grand nombre de lignes.

La conclusion est donc plus ou moins ce que j'ai mentionné plusieurs paragraphes ci-dessus ; il s'agit presque certainement d'un problème d'indexation ou de couverture d'index, éventuellement combiné à une ou plusieurs très petites tables. Ce sont les seules circonstances dans lesquelles SQL Server pourrait parfois choisir un pire plan d'exécution pour un INNER JOIN qu'un LEFT JOIN .