Jointures SQL explicites et implicites

399

Y a-t-il une différence d'efficacité entre une jointure interne explicite et implicite? Par exemple:

SELECT * FROM
table a INNER JOIN table b
ON a.id = b.id;

contre.

SELECT a.*, b.*
FROM table a, table b
WHERE a.id = b.id;
dmanxiii
la source
11
Bonne question. Je suis curieux de savoir pourquoi la jointure explicite est utilisée. N'est-il pas possible de faire toutes les requêtes sans lui?
andrew
6
utilisez le mot-clé EXPLAIN pour connaître la différence entre les deux requêtes .. utilisez JOIN et voyez la différence .. Si vous essayez dans un tableau plus de 100k enregistrements, vous pouvez voir la différence ...
Jeyanth Kumar
@andrew Ma question était en fait de savoir si la jointure implicite était une forme de "hack" (comme dans "Une requête impliquant plus d'une table, n'utilisant pas de jointure? C'est un hack n'est-ce pas?")
bobobobo
3
Ils sont différents, la jointure implicite vous surprendra de temps en temps lorsque vous aurez affaire à des valeurs nulles; utilisez la jointure explicite et évitez les bogues qui surviennent lorsque "rien ne change!"
BlackTigerX
1
Il n'y a pas de différence. ,est CROSS JOINavec une liaison plus lâche et INNER JOINest CROSS JOINavec une liaison ONsimilaire WHEREmais plus serrée. Ce qui compte pour l'exécution, c'est la façon dont le SGBD optimise les requêtes.
philipxy

Réponses:

132

En termes de performances, ils sont exactement les mêmes (au moins dans SQL Server).

PS: sachez que la IMPLICIT OUTER JOINsyntaxe est déconseillée depuis SQL Server 2005. (La IMPLICIT INNER JOINsyntaxe utilisée dans la question est toujours prise en charge)

Obsolescence de la syntaxe JOIN "à l'ancienne": une chose partielle

lomaxx
la source
4
@lomaxx, juste pour plus de clarté, pourriez-vous spécifier quelle syntaxe des 2 de la question est déconseillée?
J Wynia
8
Pouvez-vous fournir des pièces justificatives? Cela semble faux à plusieurs niveaux.
NotMe
21
Comment dépréciez-vous la norme SQL?
David Crawshaw
7
@david Crenshaw, la jointure implicite n'est plus dans la norme et ne l'est plus depuis 18 ans.
HLGEM
11
Les soi-disant «jointures implicites» de la variété «intérieure» ou «croisée» restent dans la norme. SQL Server déconseille la syntaxe de jointure externe "à l'ancienne" (c'est *=-à- dire et =*) qui n'a jamais été standard.
lorsque le
129

Personnellement, je préfère la syntaxe de jointure car elle rend plus clair que les tables sont jointes et comment elles sont jointes. Essayez de comparer des requêtes SQL plus importantes où vous sélectionnez parmi 8 tables différentes et vous avez beaucoup de filtrage dans le où. En utilisant la syntaxe de jointure, vous séparez les parties où les tables sont jointes, à la partie où vous filtrez les lignes.

grom
la source
4
Je suis entièrement d'accord, mais c'est un peu hors sujet. OP a posé des questions sur l'efficacité.
villasv
56

Sur MySQL 5.1.51, les deux requêtes ont des plans d'exécution identiques:

mysql> explain select * from table1 a inner join table2 b on a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.02 sec)

mysql> explain select * from table1 a, table2 b where a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.00 sec)

table1a 166208 lignes; table2a environ 1000 lignes.

Ceci est un cas très simple; cela ne prouve en aucun cas que l'optimiseur de requêtes ne serait pas confondu et générerait des plans différents dans un cas plus compliqué.

Matt Fenwick
la source
Ce devrait être la réponse acceptée. C'est correct, le plan est le même (ou proche de plus gros énoncés) mais la quantité d'enregistrements sera drastique, entraînant ainsi une différence de performances.
SovietFrontier
37

La seconde syntaxe a la possibilité indésirable d'une jointure croisée: vous pouvez ajouter des tables à la partie FROM sans la clause WHERE correspondante. Ceci est considéré comme dangereux.

edosoft
la source
Que faire si les noms de table dans la clause from sont générés à partir des tables utilisées dans la clause where?
Jus12
vous pouvez également effectuer une jointure croisée avec la syntaxe JOIN explicite. ( stackoverflow.com/a/44438026/929164 ) vous vouliez probablement dire qu'elle est moins stricte, donc plus sujette aux erreurs de l'utilisateur.
Daniel Dubovski
15

La première réponse que vous avez donnée utilise ce que l'on appelle la syntaxe de jointure ANSI, l'autre est valide et fonctionnera dans n'importe quelle base de données relationnelle.

Je suis d'accord avec grom que vous devez utiliser la syntaxe de jointure ANSI. Comme ils l'ont dit, la raison principale est la clarté. Plutôt que d'avoir une clause where avec de nombreux prédicats, dont certains joignent des tables et d'autres restreignent les lignes renvoyées avec la syntaxe de jointure ANSI, vous indiquez clairement quelles conditions sont utilisées pour joindre vos tables et lesquelles sont utilisées pour restreindre le résultats.

andy47
la source
5

En termes de performances, ils sont exactement les mêmes (au moins dans SQL Server), mais sachez qu'ils déconseillent cette syntaxe de jointure et qu'elle n'est pas prise en charge par SQL Server2005 dès le départ.

Je pense que vous pensez aux opérateurs * = et = * déconseillés par rapport à la "jointure externe".

Je viens de tester les deux formats donnés et ils fonctionnent correctement sur une base de données SQL Server 2008. Dans mon cas, ils ont donné des plans d'exécution identiques, mais je ne pouvais pas dire avec certitude que ce serait toujours vrai.

Joshdan
la source
5

@lomaxx: Juste pour clarifier, je suis assez certain que les deux syntaxes ci-dessus sont prises en charge par SQL Serv 2005. La syntaxe ci-dessous n'est PAS prise en charge cependant

select a.*, b.*  
from table a, table b  
where a.id *= b.id;

Plus précisément, la jointure externe (* =) n'est pas prise en charge.

deadbug
la source
2
Franchement, je ne l'utiliserais pas même dans SQL Server 2000, la syntaxe * = donne souvent de mauvaises réponses. Parfois, il les interprète comme des jointures croisées.
HLGEM
2

Sur certaines bases de données (notamment Oracle), l'ordre des jointures peut faire une énorme différence pour les performances des requêtes (s'il y a plus de deux tables). Sur une demande, nous avions littéralement deux ordres de grandeur dans certains cas. L'utilisation de la syntaxe de jointure interne vous permet de contrôler cela - si vous utilisez la bonne syntaxe des indices.

Vous n'avez pas spécifié la base de données que vous utilisez, mais la probabilité suggère SQL Server ou MySQL là où cela ne fait aucune différence réelle.

Leigh Caldwell
la source
1
Leigh, vous pouvez également utiliser les astuces dans les jointures implicites.
SquareCog
1
Dans Oracle, il est extrêmement rare que l'ordre de jointure affecte le plan d'exécution de manière significative. Voir cet article de Jonathan Lewis pour une explication.
Jon Heller
1

Comme Leigh Caldwell l'a déclaré, l'optimiseur de requêtes peut produire différents plans de requête en fonction de ce qui ressemble fonctionnellement à la même instruction SQL. Pour plus de lecture à ce sujet, jetez un œil aux deux articles de blog suivants: -

Une publication de l'équipe Oracle Optimizer

Une autre publication du blog "Structured Data"

J'espère que vous trouvez cela intéressant.

Mike McAllister
la source
Mike, la différence dont ils parlent est que vous devez être sûr que si vous spécifiez une jointure explicite, vous spécifiez la condition de jointure à laquelle se joindre, pas le filtre. Vous remarquerez que pour les requêtes sémantiquement correctes, le plan d'exécution est le même.
SquareCog
1

En termes de performances, cela ne devrait faire aucune différence. La syntaxe de jointure explicite me semble plus propre car elle définit clairement les relations entre les tables dans la clause from et n'encombre pas la clause where.

David
la source
0

Fondamentalement, la différence entre les deux est que l'un est écrit à l'ancienne, tandis que l'autre est écrit à la manière moderne. Personnellement, je préfère le script moderne utilisant les définitions interne, gauche, externe et droite car elles sont plus explicatives et rendent le code plus lisible.

Lorsqu'il s'agit de jointures internes, il n'y a pas non plus de réelle différence de lisibilité, cependant, cela peut devenir compliqué lorsque vous traitez avec des jointures gauche et droite car dans l'ancienne méthode, vous obtiendriez quelque chose comme ceci:

SELECT * 
FROM table a, table b
WHERE a.id = b.id (+);

Ce qui précède est l'ancienne façon dont une jointure gauche est écrite par opposition à ce qui suit:

SELECT * 
FROM table a 
LEFT JOIN table b ON a.id = b.id;

Comme vous pouvez le voir visuellement, la façon moderne dont le script est écrit rend la requête plus lisible. (Par ailleurs, il en va de même pour les jointures droites et un peu plus compliqué pour les jointures externes).

Pour en revenir à la plaque de la chaudière, cela ne fait aucune différence pour le compilateur SQL comment la requête est écrite car il les gère de la même manière. J'ai vu un mélange des deux dans les bases de données Oracle qui ont eu beaucoup de gens qui y écrivaient, les plus âgés et les plus jeunes. Encore une fois, cela se résume à la lisibilité du script et à l'équipe avec laquelle vous développez.

Michele La Ferla
la source
-1

D'après mon expérience, l'utilisation de la syntaxe de la clause de jointure croisée avec une clause where produit souvent un plan d'exécution endommagé par le cerveau, surtout si vous utilisez un produit Microsoft SQL. La façon dont SQL Server tente d'estimer le nombre de lignes de table, par exemple, est sauvagement horrible. L'utilisation de la syntaxe de jointure interne vous permet de contrôler la façon dont la requête est exécutée. Donc, d'un point de vue pratique, étant donné la nature atavique de la technologie de base de données actuelle, vous devez opter pour la jointure interne.

Sean
la source
5
En avez-vous une preuve? Parce que la réponse acceptée dit le contraire.
cimmanon