J'ai une table (MainTable
) avec un peu plus de 600 000 enregistrements. Il se joint à lui-même via une 2ème table (JoinTable
) dans une relation de type parent/enfant:
SELECT Child.ID, Parent.ID
FROM MainTable
AS Child
JOIN JoinTable
ON Child.ID = JoinTable.ID
JOIN MainTable
AS Parent
ON Parent.ID = JoinTable.ParentID
AND Parent.SomeOtherData = Child.SomeOtherData
Je sais que chaque enregistrement enfant a un enregistrement parent et les données de JoinTable sont précises.
Lorsque j'exécute cette requête, l'exécution prend littéralement quelques minutes. Cependant, si je me joins à Parent à l'aide d'une jointure gauche, il faut <1 seconde pour exécuter:
SELECT Child.ID, Parent.ID
FROM MainTable
AS Child
JOIN JoinTable
ON Child.ID = JoinTable.ID
LEFT JOIN MainTable
AS Parent
ON Parent.ID = JoinTable.ParentID
AND Parent.SomeOtherData = Child.SomeOtherData
WHERE ...[some info to make sure we don't select parent records in the child dataset]...
Je comprends la différence de résultats entre un INNER JOIN
et un LEFT JOIN
. Dans ce cas, il renvoie exactement le même résultat que chaque enfant a un parent. Si je laisse les deux requêtes s'exécuter, je peux comparer les ensembles de données et ils sont exactement les mêmes.
Pourquoi est-ce qu'un LEFT JOIN
tourne tellement plus vite qu'un INNER JOIN
?
MISE À JOUR Vérifiez les plans de requête et lorsque vous utilisez une jointure interne, elle commence par l'ensemble de données parent. Lorsque vous effectuez une jointure gauche, elle commence par l'ensemble de données enfant.
Les index qu'il utilise sont tous les mêmes.
Puis-je l'obliger à toujours commencer avec l'enfant? L'utilisation d'une jointure gauche fonctionne, cela ne semble pas correct.
Des questions similaires ont déjà été posées ici, mais aucune ne semble répondre à ma question.
par exemple. la réponse sélectionnée dans INNER JOIN vs performances LEFT JOIN dans SQL Server indique que les jointures gauches sont toujours plus lentes que les jointures internes. L'argument est logique, mais ce n'est pas ce que je vois.
La jointure gauche semble être plus rapide car SQL est obligé de faire d'abord la sélection la plus petite, puis de se joindre à ce petit ensemble d'enregistrements. Pour une raison quelconque, l'optimiseur ne veut pas le faire naturellement.
3 façons de forcer les jointures à se produire dans le bon ordre:
Essaye celui-là. Même résultat, approche différente:
SELECT c.ID, p.ID
FROM
(SELECT Child.ID, JoinTable.ParentID
FROM MainTable
AS Child
JOIN JoinTable
ON Child.ID = JoinTable.ID) AS c
INNER JOIN
(SELECT Parent.ID, JoinTable.ID
FROM MainTable
AS Parent
JOIN JoinTable
ON Parent.ID = JoinTable.ParentID
AND Parent.SomeOtherData = Child.SomeOtherData) AS p
ON c.ParentID = p.ID
Si cela n'aide pas, utilisez cte:
;WITH cte AS
(SELECT Child.ID, JoinTable.ParentID
FROM MainTable
AS Child
JOIN JoinTable
ON Child.ID = JoinTable.ID)
SELECT cte.ID, Parent.ID
FROM cte INNER JOIN
MainTable
AS Parent
ON Parent.ID = cte.ParentID
AND Parent.SomeOtherData = cte.SomeOtherData