web-dev-qa-db-fra.com

Condition dans JOIN ou WHERE

Existe-t-il une différence (performances, meilleures pratiques, etc.) entre l’imposition d’une condition dans la clause JOIN et la clause WHERE?

Par exemple...

-- Condition in JOIN
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
AND CUS.FirstName = 'John'

-- Condition in WHERE
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE CUS.FirstName = 'John'

Lequel préférez-vous (et peut-être pourquoi)?

157
Steve Dignan

L'algèbre relationnelle permet l'interchangeabilité des prédicats de la clause WHERE et du INNER JOIN. Ainsi, même les requêtes INNER JOIN avec des clauses WHERE peuvent avoir les prédicats réarrangés de telle sorte qu'ils puissent déjà être exclus pendant le processus JOIN.

Je vous recommande d'écrire les requêtes de la manière la plus lisible possible.

Parfois, cela implique de rendre le INNER JOIN relativement "incomplet" et de mettre certains des critères dans la variable WHERE simplement pour rendre les listes de critères de filtrage plus faciles à gérer.

Par exemple, au lieu de:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
    AND c.State = 'NY'
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
    AND a.Status = 1

Écrire:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
WHERE c.State = 'NY'
    AND a.Status = 1

Mais cela dépend, bien sûr.

129
Cade Roux

Pour les jointures internes, je n'ai pas vraiment remarqué de différence (mais, comme pour tout réglage des performances, vous devez vérifier votre base de données dans certaines conditions).

Toutefois, l'emplacement de la condition fait une énorme différence si vous utilisez des jointures à gauche ou à droite. Par exemple, considérons ces deux requêtes:

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderDate >'20090515'

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
AND ORD.OrderDate >'20090515'

La première ne vous donnera que les enregistrements dont l'ordre est daté du 15 mai 2009, convertissant ainsi la jointure gauche en une jointure interne. La seconde donnera ces enregistrements ainsi que tous les clients sans commande. Les résultats sont très différents selon l'endroit où vous avez placé la condition. (Sélectionnez * si, à titre d'exemple uniquement, vous ne devez pas utiliser de code de production.) L'exception à cette règle est lorsque vous souhaitez afficher uniquement les enregistrements d'une table mais pas de l'autre. Ensuite, vous utilisez la clause where pour la condition et non pour la jointure. 

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderID is null
101
HLGEM

La plupart des produits de SGBDR optimisent les deux requêtes de manière identique. Dans "SQL Performance Tuning" de Peter Gulutzan et Trudy Pelzer, ils ont testé plusieurs marques de SGBDR et n'ont constaté aucune différence de performances.

Je préfère séparer les conditions de jointure des conditions de restriction de requête.

Si vous utilisez OUTER JOIN, il est parfois nécessaire de définir des conditions dans la clause join.

23
Bill Karwin

WHERE filtrera une fois que la jointure a eu lieu.

Filtrez sur JOIN pour empêcher l'ajout de lignes pendant le processus JOIN.

11
TheTXI

Je préfère que JOIN rejoigne des tables/vues complètes, puis utilise WHERE pour introduire le prédicat de l'ensemble résultant.

Il se sent syntaxiquement plus propre.

3
Johnno Nolan

Je constate généralement une augmentation des performances lors du filtrage sur la jointure. Surtout si vous pouvez joindre des colonnes indexées pour les deux tables. Cela devrait également vous permettre de réduire les lectures logiques, ce qui constitue, dans un environnement à volume élevé, un indicateur de performance bien meilleur que le temps d'exécution.

Je suis toujours légèrement amusé lorsque quelqu'un montre son analyse comparative SQL et qu'il a exécuté les deux versions d'un sproc 50 000 fois à minuit sur le serveur de développement et compare les temps moyens.

2
marr75

Mettre la condition dans la jointure me semble "sémantiquement faux", car ce n'est pas ce que les JOIN sont "pour". Mais c'est très qualitatif.

Problème supplémentaire: si vous décidez de passer d'une jointure interne à une jointure droite, par exemple, le fait que la condition soit dans le JOIN peut entraîner des résultats inattendus.

0
Jacob B

Il est préférable d’ajouter la condition dans la jointure. Les performances sont plus importantes que la lisibilité. Pour les grands ensembles de données, c'est important.

0
Jeeno Shibu

Les jointures sont plus rapides à mon avis lorsque vous avez une table plus grande. Ce n’est vraiment pas une si grande différence, surtout s’il s’agit d’un tableau un peu plus petit. Quand j'ai appris pour la première fois sur les jointures, on m'a dit que les conditions dans les jointures sont comme si les conditions de clause et que je pouvais les utiliser de manière interchangeable si la clause where était spécifique à la table sur laquelle appliquer la condition.

0
Eric