web-dev-qa-db-fra.com

Utiliser ou non le mot clé JOIN

Les requêtes SQL suivantes sont identiques:

SELECT column1, column2
FROM table1, table2
WHERE table1.id = table2.id;

SELECT column1, column2
FROM table1 JOIN table2 
ON table1.id = table2.id;

Et il en résulte certainement les mêmes plans de requête sur tous les SGBD que j'ai jamais essayés.

Mais de temps en temps, je lis ou j'entends une opinion que l'un est définitivement meilleur que l'autre. Naturellement, ces affirmations ne sont jamais étayées par une explication.

Là où je travaille, la deuxième version semble être favorisée par la majorité des autres développeurs, et j'ai donc tendance à privilégier ce style pour minimiser les surprises. Mais dans mon cœur, je pense vraiment au premier (puisque c'est comme ça que je l'ai appris à l'origine).

L'une de ces formes est-elle objectivement meilleure que l'autre? Sinon, quelles seraient les raisons d'utiliser l'un sur l'autre?

Je trouve que la deuxième forme est meilleure. C'est peut-être parce que c'est ainsi que je l'ai appris, je l'admets, mais j'ai une raison concrète: la séparation des préoccupations. Placer les champs que vous utilisez pour joindre les tables dans la clause where peut entraîner des difficultés pour comprendre les requêtes.

Par exemple, prenez la requête suivante:

select *
from table1, table2, table3, table4
where table1.id = table2.id
and table2.id = table3.id
and table3.id = table4.id
and table1.column1 = 'Value 1'

La requête ci-dessus a des conditions de jointure de table et des conditions de logique métier réelles toutes combinées en un seul espace. Avec une requête volumineuse, cela peut être très difficile à comprendre.

Cependant, prenez maintenant ce code:

select *
from table1 join table2 on table1.id = table2.id
join table3 on table2.id = table3.id
join table4 on table3.id = table4.id
where table1.column1 = 'Value 1'

Dans ce cas, tout ce qui concerne les tables ou leur relation est tout isolé de la clause from, tandis que la logique métier réelle pour la restriction de requête se trouve dans la clause where. Je pense que c'est juste beaucoup plus compréhensible, en particulier pour les requêtes plus importantes.

62
Dustin Wilhelmi

La syntaxe de jointure a remplacé l'ancienne syntaxe de virgule en 1992. Il n'y a actuellement aucune raison d'écrire du code avec la syntaxe de virgule. Vous ne gagnez rien et vous êtes sujet à des problèmes que vous n'avez tout simplement pas avec la syntaxe explicite.

En premier lieu, lorsque vous obtenez des requêtes plus compliquées, il est très facile de faire une jointure croisée accidentelle en manquant une condition where. C'est quelque chose que la syntaxe de jointure explicite peut empêcher de se produire car vous obtiendrez une erreur de syntaxe.

Si vous envisagez une jointure croisée, la syntaxe de jointure explicite le précisera tandis que dans la syntaxe implicite, une personne effectuant la maintenance peut supposer que vous avez oublié d'ajouter la clause where.

Ensuite, il y a le problème des jointures gauche et droite qui sont problématiques dans au moins certains dbs utilisant la syntaxe implicite. Ils sont dépréciés dans SQL Server et, en fait, ne renvoient pas correctement les résultats, même dans les anciennes versions. Aucune requête nécessitant une jointure externe ne doit contenir la syntaxe implicite dans SQL Server.

De plus, j'ai vu des questions ici et sur d'autres sites où de mauvais résultats se sont produits lorsque les gens mélangent les jointures implicites et explicites (lors de l'ajout d'une jointure gauche par exemple), donc c'est une mauvaise idée de les mélanger.

Enfin, de nombreuses personnes qui utilisent des jointures implicites ne comprennent pas réellement les jointures. Il s'agit d'une compréhension critique que vous devez avoir pour interroger efficacement une base de données.

40
HLGEM

Ha. Je viens de trouver une réponse possible à ma propre question, tout en regardant la documentation de PostgreSQL . Pour résumer ce que cette page explique, la requête résultante est toujours la même, mais le nombre de plans que l'optimiseur doit considérer augmente exponentiellement avec le nombre de jointures.

Après environ six jointures de ce type, le nombre est si élevé que le temps de planification de la requête peut être perceptible, et après une dizaine, l'optimiseur passera d'une recherche exhaustive de plans à une recherche probabiliste et risque de ne pas arriver sur le plan optimal. .

En définissant un paramètre d'exécution, vous pouvez demander au planificateur de traiter les jointures internes et croisées mentionnées explicitement différemment des jointures implicites, en les forçant en haut du plan et sans explorer d'autres options.

Il convient de noter que le comportement par défaut est le même dans les deux cas, et que l'obtention de plans alternatifs nécessite une connaissance des internes des dbms et des particularités des tables en question pour obtenir un résultat différent

Eh bien voici la vue de la théorie des ensembles:

Lorsque vous utilisez une virgule pour séparer deux (ou plusieurs) noms de table, ce que vous prévoyez est le produit cartésien. Chaque ligne du tableau "gauche" sera "mise en correspondance" (concaténée) avec celle du tableau de droite.

Maintenant, si vous écrivez quelque chose dans la clause where, c'est comme mettre une condition sur cette "concaténation" indiquant quelles lignes "concaténer" avec quelles lignes.

Il s'agit en fait de "joindre" les lignes :) et donc le mot clé join qui aide à fournir une syntaxe plus lisible et est plus compréhensible que vous souhaitiez "en effet" rejoindre certaines valeurs communes. Similaire à ce que @Dustin a clarifié ci-dessus.

Maintenant, chaque SGBD est intelligent, c'est-à-dire qu'il ne calcule pas le produit cartésien en premier, puis filtre les données (extrêmement inutile), mais le fait plutôt en fonction de la structure de la requête. La seule chose à laquelle je peux penser est que lorsque vous lui demandez de `` rejoindre '', c'est comme rendre l'activité de jointure explicite et aide probablement à exécuter le code plus rapidement (de combien? Vous devrez le profiler et voir), mais dans le cas séparés par des virgules, il faut un certain temps pour "comprendre" la stratégie optimale. Je me trompe peut-être, mais je fais juste une supposition éclairée sur la façon de le coder ...

8
PhD

Je pense qu'il est généralement préférable d'utiliser des instructions JOIN pour ce cas.

Si, à l'avenir, une situation se produit qui nécessite de changer l'instruction d'une INNER JOIN à une OUTER JOIN, cela sera beaucoup plus facile à faire avec la deuxième instruction.

5
Britt Wescott

Tout SGBDR va faire en sorte qu'ils soient la même chose en termes d'exécution. Il s'agit de savoir si l'on est plus lisible et expressif.

Utilisez JOIN pour savoir clairement ce qu'est la correspondance de jointure et quelle est la sélection réelle, comme dans:

select name, deptname
from people p, departments d
where p.deptid = d.id and p.is_temp = 'Y'

vs.

select name, deptname
from people p
    inner join departments d on p.deptid = d.id
where p.is_temp = 'Y'

Ce dernier cas indique immédiatement quelle est la condition de jointure et quel est le critère de sélection.

3
Andy Lester

Je n'ai vu qu'une seule fois les deux résultats dans un ensemble d'optimisations différent et si la mémoire est bonne, c'était en ms-sql2k sur une requête vraiment velue. Dans cet exemple, l'ancien formulaire utilisé avec * = a entraîné des performances environ 4 fois plus rapides. Personne, y compris nos techniciens Microsoft, n'a jamais pu expliquer pourquoi. Les gars de la SP l'ont étiqueté comme une erreur. Je ne l'ai jamais revu.

Étant donné que la plupart des SGBDR sont suffisamment intelligents pour ne pas faire les cartésiens complets, la principale raison pour laquelle je peux penser à ne pas l'utiliser (à part qu'il est déprécié) est que la plupart des personnes de moins de 30 à 35 ans avec lesquelles j'ai travaillé n'ont jamais vu le ancienne forme avant et se perdre terriblement quand ils le rencontrent.

1
Bill