INNER JOIN on vs WHERE clause

Pour simplifier, supposons que tous les champs pertinents sont NOT NULL.

Vous pouvez faire:

SELECT
    table1.this, table2.that, table2.somethingelse
FROM
    table1, table2
WHERE
    table1.foreignkey = table2.primarykey
    AND (some other conditions)

Ou bien:

SELECT
    table1.this, table2.that, table2.somethingelse
FROM
    table1 INNER JOIN table2
    ON table1.foreignkey = table2.primarykey
WHERE
    (some other conditions)

Est-ce que ces deux fonctionnent de la même manière dans MySQL?

778
demandé sur Uwe Keim 2009-06-19 20:16:24

10 réponses

INNER JOIN est la syntaxe ANSI que vous devez utiliser.

Il est généralement considéré comme plus lisible, surtout lorsque vous joignez beaucoup de tables.

Il peut également être facilement remplacé par un OUTER JOIN en cas de besoin.

La syntaxe WHERE est plus orientée vers le modèle relationnel.

Un résultat de deux tables JOIN ed est un produit cartésien des tables auxquelles un filtre est appliqué qui sélectionne uniquement les lignes avec des colonnes de jointure correspondant.

Il est plus facile de voir cela avec la syntaxe WHERE.

Quant à votre exemple, dans MySQL (et dans SQL en général) ces deux requêtes sont synonymes.

Notez également que MySQL a également une clause STRAIGHT_JOIN.

En utilisant cette clause, vous pouvez contrôler l'ordre JOIN: quelle table est scannée dans la boucle externe et laquelle est dans la boucle interne.

Vous ne pouvez pas contrôler cela dans MySQL en utilisant la syntaxe WHERE.

622
répondu Quassnoi 2017-11-19 16:28:17

D'autres ont souligné que INNER JOIN aide la lisibilité humaine, et c'est une priorité absolue; je suis d'accord. Laissez-moi vous expliquer pourquoi la syntaxe de jointure est plus lisible.

Une requête de sélection de base est la suivante:

SELECT stuff
FROM tables
WHERE conditions

La clause SELECT nous indique ce que nous récupérons; la clause FROM nous indique nous l'obtenons, et la clause WHERE nous indique quels ceux que nous obtenons.

JOIN est une déclaration sur les tables, comment elles sont liées ensemble (conceptuellement, en fait, dans une seule table). Tous les éléments de requête qui contrôlent les tables - d'où nous recevons des choses-appartiennent sémantiquement à la clause FROM (et bien sûr, c'est là que vont les éléments de jointure). Mettre des éléments de jointure dans la clause WHERE confond le which et le where-from ; c'est pourquoi la syntaxe de jointure est préférée.

149
répondu Carl Manaster 2009-06-19 16:30:59

Application d'instructions conditionnelles dans ON / WHERE

Ici, j'ai expliqué les étapes de traitement de la requête logique.


Référence: Inside Microsoft® SQL Server™ 2005 T-SQL interrogation
Éditeur: Microsoft Press
Pub Date: 07 Mars 2006
Imprimer ISBN-10: 0-7356-2313-9
Imprimer ISBN-13: 978-0-7356-2313-2
Pages: 640

Dans Microsoft ® SQL Server™ 2005 T-SQL interrogation

(8)  SELECT (9) DISTINCT (11) TOP <top_specification> <select_list>
(1)  FROM <left_table>
(3)       <join_type> JOIN <right_table>
(2)       ON <join_condition>
(4)  WHERE <where_condition>
(5)  GROUP BY <group_by_list>
(6)  WITH {CUBE | ROLLUP}
(7)  HAVING <having_condition>
(10) ORDER BY <order_by_list>

Le premier notable aspect de SQL qui est différent des autres langages de programmation est l'ordre dans lequel le code est traité. Dans la plupart des langages de programmation, le code est traité dans l'ordre dans lequel il est écrit. En SQL, la première clause traitée est la clause FROM, tandis que la clause SELECT, qui apparaît en premier, est traitée presque en dernier.

Chaque étape génère une table virtuelle qui est utilisée comme entrée pour l'étape suivante. Ces tables virtuelles ne sont pas disponibles pour l'appelant (client application ou requête externe). Seule la table générée par l'étape finale est renvoyée à l'appelant. Si une clause n'est pas spécifié dans une requête, l'étape correspondante est simplement ignorée.

Brève Description des Phases de traitement des requêtes logiques

Ne vous inquiétez pas trop si la description des étapes ne semble pas avoir beaucoup de sens pour l'instant. Ces sont fournies à titre de référence. Les Sections qui viennent après l'exemple de scénario couvriront les étapes dans beaucoup plus détail.

  1. FROM: un produit cartésien (CROSS join) est effectué entre les deux premières tables de la clause FROM et, par conséquent, la table virtuelle VT1 est générée.

  2. ON: le filtre ON est appliqué à VT1. Seules les lignes pour lesquelles <join_condition> est TRUE sont insérées dans VT2.

  3. OUTER (join): si une jointure externe est spécifiée (par opposition à une jointure croisée ou une jointure interne), les lignes de la ou des tables conservées pour lesquelles une correspondance n'a pas été trouvée sont ajoutées à les lignes de VT2 en tant que lignes externes, générant VT3. Si plus de deux tables apparaissent dans la clause FROM, les étapes 1 à 3 sont appliquées de manière répétée entre le résultat de la dernière jointure et la table suivante de la clause FROM jusqu'à ce que toutes les tables soient traitées.

  4. Où: le filtre WHERE est appliqué à VT3. Seules les lignes pour lesquelles <where_condition> est TRUE sont insérées dans VT4.

  5. GROUP BY: les lignes de VT4 sont organisées en groupes en fonction de la liste de colonnes spécifiée dans GROUP BY clause. VT5 est généré.

  6. CUBE / ROLLUP: Supergroups (groupes de groupes) sont ajoutés aux lignes de VT5, générant VT6.

  7. HAVING: le filtre HAVING est appliqué à VT6. Seuls les groupes pour lesquels <having_condition> est TRUE sont insérés dans VT7.

  8. SELECT: la liste SELECT est traitée, générant VT8.

  9. DISTINCT: les lignes en double sont supprimées de VT8. VT9 est généré.

  10. Trier par: les lignes de VT9 sont triées selon la liste de colonnes spécifiée dans la clause ORDER BY. Un curseur est généré (VC10).

  11. Haut: le nombre ou le pourcentage spécifié de lignes est sélectionné à partir du début de VC10. La Table VT11 est générée et renvoyée à l'appelant.



Par conséquent, (INNER JOIN) on filtrera les données (le nombre de données de VT sera réduit ici lui-même) avant d'appliquer la clause WHERE. Les conditions de jointure suivantes seront exécutées avec filtered données qui améliore les performances. Après cela, seule la condition WHERE appliquera les conditions de filtre.

(L'application d'instructions conditionnelles dans ON / WHERE ne fera pas beaucoup de différence dans quelques cas. Cela dépend du nombre de tables que vous avez jointes et du nombre de lignes disponibles dans chaque table de jointure)

115
répondu rafidheen 2015-09-28 18:38:37

La syntaxe ANSI de jointure implicite est plus ancienne, moins évidente et non recommandée.

En outre, l'algèbre relationnelle permet l'interchangeabilité des prédicats dans le WHERE clause et la INNER JOIN, de sorte que même INNER JOIN requêtes avec WHERE clauses peuvent avoir les prédicats rearrranged par l'optimiseur.

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

Parfois, cela inclut de rendre le INNER JOIN relativement "incomplet" et de mettre certains des critères dans le WHERE simplement pour rendre les listes de critères de filtrage plus facilement maintenables.

, 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 ça dépend, bien sûr.

55
répondu Cade Roux 2009-06-19 16:23:45

Les jointures implicites (ce que votre première requête est appelée) deviennent beaucoup plus confuses, difficiles à lire et difficiles à maintenir une fois que vous devez commencer à ajouter plus de tables à votre requête. Imaginer faire la même requête et le type de jointure sur quatre ou cinq tableaux ... c'est un cauchemar.

L'utilisation d'une jointure explicite (votre deuxième exemple) est beaucoup plus lisible et facile à maintenir.

26
répondu matt b 2009-06-19 16:19:14

Je soulignerai également que l'utilisation de l'ancienne syntaxe est plus sujette à erreur. Si vous utilisez des jointures internes sans clause ON, vous obtiendrez une erreur de syntaxe. Si vous utilisez l'ancienne syntaxe et d'oublier l'une des conditions de jointure dans la clause where, vous obtiendrez une jointure croisée. Les développeurs corrigent souvent cela en ajoutant le mot-clé distinct (plutôt que de réparer la jointure car ils ne réalisent toujours pas que la jointure elle-même est cassée) qui peut sembler guérir le problème, mais ralentira la requête considérablement.

De plus pour la maintenance si vous avez une jointure croisée dans l'ancienne syntaxe, comment le mainteneur saura-t-il si vous vouliez en avoir une (il y a des situations où des jointures croisées sont nécessaires) ou si c'était un accident qui devrait être corrigé?

Permettez-moi de vous indiquer cette question pour voir pourquoi la syntaxe implicite est mauvaise si vous utilisez left jointures. Sybase * = à la norme Ansi avec 2 tables externes différentes pour la même table intérieure

Plus (diatribe personnelle ici), la norme l'utilisation des jointures explicites a plus de 20 ans, ce qui signifie que la syntaxe de jointure implicite est obsolète depuis ces 20 ans. Voulez-vous écrire du code d'application en utilisant une syntaxe obsolète depuis 20 ans? Pourquoi voulez-vous écrire du code de base de données?

22
répondu HLGEM 2017-05-23 12:02:50

Ils ont une signification différente lisible par l'homme.

Cependant, en fonction de l'optimiseur de requête, ils peuvent avoir la même signification pour la machine.

Vous devez toujours coder pour être lisible.

C'est-à-dire, s'il s'agit d'une relation intégrée, utilisez la jointure explicite. si vous correspondez sur des données faiblement liées, utilisez la clause where.

12
répondu John Gietzen 2010-04-15 22:04:49

La norme SQL: 2003 a modifié certaines règles de priorité, de sorte qu'une instruction JOIN a priorité sur une jointure "virgule". Cela peut réellement changer les résultats de votre requête en fonction de la façon dont il est configuré. Cela cause des problèmes pour certaines personnes lorsque MySQL 5.0.12 est passé à adhérer à la norme.

Donc, dans votre exemple, vos requêtes fonctionneraient de la même manière. Mais si vous avez ajouté un troisième tableau: SÉLECTIONNER ... De table1, table2 joindre table3 sur ... OÙ ...

Avant MySQL 5.0.12, table1 et table2 serait joint en premier, puis table3. Maintenant (5.0.12 et on), table2 et table3 sont joints en premier, puis table1. Cela ne change pas toujours les résultats, mais cela peut et vous ne pouvez même pas le réaliser.

Je n'utilise plus jamais la syntaxe" virgule", en optant pour votre deuxième exemple. C'est beaucoup plus lisible de toute façon, les conditions de jointure sont avec les jointures, pas séparées dans une section de requête séparée.

10
répondu Brent Baisley 2009-06-19 17:28:56

Je sais que vous parlez de MySQL, mais de toute façon: Dans Oracle 9, les jointures explicites et les jointures implicites généreraient différents plans d'exécution. AFAIK qui a été résolu dans Oracle 10+: il n'y a plus une telle différence.

4
répondu João Marcus 2009-06-19 17:03:42

ANSI join syntaxe est certainement plus portable.

Je passe par une mise à niveau de Microsoft SQL Server, et je mentionnerais également que la syntaxe =* et *= pour les jointures externes dans SQL Server n'est pas prise en charge (sans mode de compatibilité) pour 2005 sql server et versions ultérieures.

1
répondu Benzo 2009-06-19 16:50:12