Existe-t-il une différence importante entre les requêtes jointes par les clauses WHERE et les requêtes utilisant un JOIN réel?

32

Dans Learn SQL the Hard Way (exercice 6) , l'auteur présente la requête suivante:

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

et continue ensuite en disant que:

Il existe en fait d'autres moyens pour faire fonctionner ce type de requête, appelé "jointure". J'évite ces concepts pour l'instant car ils sont incroyablement déroutants. Tenez-vous-en à cette façon de joindre les tables pour le moment et ignorez les personnes qui essaient de vous dire que cela est en quelque sorte plus lent ou "de classe inférieure".

Est-ce vrai? Pourquoi ou pourquoi pas?

Robert Harvey
la source
3
Je ne pense pas qu'il y en ait un, mais vous pouvez essayer de faire un EXPLAIN pour voir s'il y a une différence dans l'exécution de la requête.
GrandmasterB
6
J'aimerais souligner les signaux contradictoires d'une œuvre avec "The Hard Way" dans le titre en sautant un concept "parce qu'ils sont incroyablement déroutants". Mais peut-être que juste ma conception de ce que "la voie dure" devrait être est fausse. Mais encore une fois, peut-être pas.
Mindwin
7
JOIN transporte très bien l'intention (tables de jointure), ce qui laisse la partie WHERE pour les filtres réels et la rend un peu plus facile à lire. (outre de nombreuses autres implications)
Mardi
2
Vous apprenez le langage SQL à la dure, si son auteur ne veut pas se soucier d’écrire des jointures simples! Comme ThomasS le dit en utilisant des JOINs, les intentions sont clarifiées et les clauses WHERE deviennent beaucoup plus simples. De plus, l'utilisation de JOIN illustre mieux la théorie des ensembles qui sous-tend SQL.
Daniel Hollinrake
1
Je ne suis pas sûr de ce que je ressens à propos de quelque chose qui est censé vous apprendre quelque chose en disant "Mais bon, nous allons sauter ce concept fondamental parce que c'est de la banane craaazzzyyyy." Je pense que je finirais par chercher une source différente pour apprendre. À un moment donné, vous devez faire des jointures externes et croisées et savoir comment les faire.
Maurice Reeves

Réponses:

23

Avec l’approche de l’auteur, l’enseignement des OUTER JOINs devient beaucoup plus difficile. La clause ON dans INNER JOIN ne m'a jamais déconcerté comme beaucoup d'autres choses. Peut-être que c'est parce que je n'ai jamais appris à l'ancienne. J'aimerais penser qu'il y a une raison pour laquelle nous nous en sommes débarrassés et que ce n'était pas pour être méchant et appeler cette méthode classe inférieure.

C'est vrai dans le scénario très étroit que l'auteur a créé:

  • Un tel niveau d'entrée de SQL que l'utilisation de ON est complexe
  • Considérer seulement JOIN / INNER JOIN et non des jointures externes
  • Le codeur isolé qui n'a pas à lire le code d'un autre utilisateur, ni de personnes expérimentées dans l'utilisation de ON, lit / utilise leur code.
  • Ne nécessitant pas de requêtes complexes avec beaucoup de: tables, si, mais et ou ou.

Dans le cadre d’une progression d’enseignement, je pense qu’il est plus facile de la décomposer et d’avoir une progression naturelle:

Select * from table
select this, something, that from table
select this from table where that = 'this'
select this from table join anothertable on this.id = that.thisid

Les concepts de jonction et de filtrage des tables ne sont pas vraiment les mêmes. L' apprentissage de la syntaxe correcte va maintenant avoir plus de report quand vous apprenez REJOINT à moins que l'OUTER auteur a l' intention d'enseigner des choses obsolètes / désapprouvées comme: *= or =*.

JeffO
la source
5
La raison pour laquelle l'instruction JOIN a été ajoutée est qu'il n'existait aucune norme pour l'expression des jointures externes. Chaque fournisseur de base de données disposait donc de sa propre syntaxe "spéciale" (incompatible). IIRC Oracle avait *=ou =*indiquait des jointures externes gauches ou droites, un autre que j’utilisais ne supportait que les jointures externes gauches à l’aide d’un |=opérateur.
TMN
1
@TMN IIRC Oracle utilisé +=ou peut-être était-il =+. Je crois que *=c'était Transact-SQL (Sybase et plus tard MS-SQL). Toujours, bon point.
David
1
Là où ça commence à devenir compliqué (IMHO), c'est quand vous avez un mélange de jointures internes et externes. Dans ce type de situation, je vous avouerai que je retombe parfois dans la technique de la "classe inférieure" pour effectuer mes jointures dans la WHEREclause. (J'ai entendu parler de cela comme une adhésion thêta , mais je ne suis pas sûr que ce soit correct.)
David
Les opérateurs IIRC tels que "supérieur à" ou "égal à" étaient parfois appelés "opérateurs thêta", mais une recherche sur Google conduit à une opération de calcul.
Walter Mitty
12

Que cela soit plus lent dépend de l'optimiseur de requête et de la façon dont il rationalise la requête (ce que vous écrivez n'est pas ce qui est exécuté). Cependant, le gros problème de cette citation est qu’elle ignore complètement le fait qu’il existe différents types de jointures qui fonctionnent de manière totalement différente. Par exemple, ce qui est dit est (théoriquement) vrai pour inner joins, mais ce n'est pas vrai pour outer joins( left joinset right joins).

Locke
la source
9
+1 Pour les autres types de jointures. La plupart de mes jointures sont soit INNER JOINou LEFT OUTER JOIN. Ils ne sont pas "incroyablement déroutants". SQL peut devenir incroyablement déroutant, mais ce n’est pas un exemple.
mgw854
hors sujet , mais la déclaration doit être différents types de jointure s ou types de rejoindre ?
user1451111
9

L'auteur présente un cas simple d'utilisation de l'ancienne ou de la nouvelle syntaxe. Je ne suis pas d'accord sur son affirmation selon laquelle les jointures sont source de confusion insensée, car la jonction de tables est un concept fondamental de requête SQL. Donc, l’auteur aurait peut-être dû passer un peu de temps à expliquer le fonctionnement de JOINS avant de prononcer une déclaration avec opinion, ainsi qu’à faire un exemple de requête à plusieurs tables.

Il faut utiliser la syntaxe la plus récente. L'argument principal est que votre requête aura:

  • Sélectionner des critères
  • Rejoindre les critères
  • Critères de filtrage

À l'aide de l'ancien style, les critères de jointure et de filtrage sont combinés, ce qui peut conduire à la confusion dans des cas plus complexes.

En outre, on peut obtenir un produit cartésien en oubliant un critère de jointure dans la clause de filtre:

 person_pet.person_id = person.id

en utilisant l'ancienne syntaxe.

L'utilisation de la nouvelle syntaxe spécifie également comment la jointure doit se produire, ce qui est important pour savoir si vous voulez un INNER, un LEFT OUTER, etc., de sorte qu'il est plus explicite en ce qui concerne la syntaxe JOIN qui améliore la lisibilité pour ceux qui ne connaissent pas les tables de jointure.

Jon Raynor
la source
5

Cela ne devrait pas être le cas, l'analyseur de requête devrait générer une représentation interne équivalente pour les requêtes équivalentes, quelle que soit leur écriture. L'auteur n'utilise que la syntaxe pré-SQL-92, raison pour laquelle il mentionne qu'elle pourrait être considérée comme "à l'ancienne" ou "basse classe". En interne, l'analyseur et l'optimiseur doivent générer le même plan de requête.

RGT
la source
5

J'ai appris SQL de cette façon, y compris le *= syntaxe des jointures externes. Pour moi, c'était très intuitif puisque toutes les relations ont la même priorité et permettent de mieux configurer les requêtes en une série de questions: que voulez-vous? D'où les voulez-vous? Lesquel tu veux?

En faisant de la joinsyntaxe, cela perturbe plus fortement le processus de pensée envers les relations. Et personnellement, je trouve le code beaucoup moins lisible avec les tables et les relations mélangées.

Au moins dans MSSQL, il n'y a aucune différence significative dans les performances des requêtes, en supposant que vous utilisiez le même ordre de jointure. Cela dit, l’ apprentissage (et l’utilisation) de SQL de cette manière pose un énorme problème. Si vous oubliez une de vos relations, vous obtiendrez des produits croisés inattendus. Qui sur une base de données de toute taille non-triviale est prohibitif (et dangereux pour les non-sélectionnés!). Il est beaucoup plus difficile d'oublier une relation lorsque vous utilisez la joinsyntaxe de style.

Telastyn
la source
7
C'est une base de données relationnelle , les relations sont donc très importantes pour une requête. Personnellement, j'ai beaucoup plus de mal à comprendre une requête qui mélange de vrais filtres (foo.x = 5) à des relations (foo.x = bar.x). Le moteur peut facilement optimiser cela dans une jointure, mais un humain doit essentiellement en raisonner ligne par ligne, par opposition à des ensembles et des sous-ensembles.
Aaronaught
4

Il convient de prendre en compte deux aspects différents: performances et maintenabilité / lisibilité .

Maintenabilité / lisibilité

J'ai choisi une requête différente, car je pense que c'est un exemple meilleur / pire que la requête d'origine que vous avez postée.

Qu'est-ce qui vous va le mieux et qui est plus lisible?

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e
inner join HumanResources.EmployeeDepartmentHistory edh
on e.BusinessEntityID = edh.BusinessEntityID
inner join HumanResources.Department d
on edh.DepartmentID = d.DepartmentID
where d.Name = 'Engineering';

Ou...

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e, 
HumanResources.EmployeeDepartmentHistory edh,
HumanResources.Department d
where e.BusinessEntityID = edh.BusinessEntityID
and edh.DepartmentID = d.DepartmentID
and d.Name = 'Engineering';

Pour moi personnellement, le premier est assez lisible. Vous voyez que nous joignons des tables avec INNER JOIN, ce qui signifie que nous extrayons les lignes qui correspondent à la clause de jointure suivante (c'est-à-dire "rejoindre un employé avec EmployeeDepartmentHistory sur BusinessEntityID et inclure ces lignes").

Ce dernier, la virgule ne signifie rien pour moi. Je me demande ce que vous faites avec tous ces WHEREprédicats d’article.

Le premier lit plus comme mon cerveau pense. Je regarde SQL toute la journée, tous les jours, ainsi que les virgules pour les jointures. Ce qui m'amène à mon prochain point ...

Il existe en fait d'autres moyens pour faire fonctionner ce type de requête, appelés "jointures".

Ils sont tous joints. Même les virgules sont une jointure. Le fait que l'auteur ne les appelle pas, c'est bien leur perte ... ce n'est pas évident. Cela devrait être évident. Vous joignez des données relationnelles, que vous spécifiiez JOINou ,.

Performance

Cela dépendra très certainement du SGBDR. Je ne peux parler qu'au nom de Microsoft SQL Server. Les performances sont équivalentes. Comment le sais-tu? Capturez les plans de post-exécution et voyez ce que SQL Server fait exactement pour chacune de ces instructions:

entrez la description de l'image ici

Dans l'image ci-dessus, j'ai souligné que j'utilise les deux requêtes comme ci-dessus, ne différant que par les caractères explicites de la jointure ( JOINvs ,). SQL Server fait exactement la même chose.

Sommaire

N'utilisez pas de virgules. Utilisez des JOINdéclarations explicites .

Thomas Stringer
la source
J'ai appris INNER JOINs bien avant de comprendre que la variante avec les clauses WHERE était équivalente et vos deux exemples me paraissaient très lisibles. Celui avec les WHERE et les virgules pourrait être encore plus lisible. Je pense que le problème est qu’il s’agit de requêtes complexes et volumineuses, et non de requêtes relativement simples.
Robert Harvey
Le fait est de penser que la variation par virgule n'est pas une jointure relationnelle n'est pas correcte du tout.
Thomas Stringer
Je pense que vous interprétez incorrectement les virgules comme des jointures. Les virgules se contentent de séparer les tableaux. ce sont les conditions WHERE qui créent les jointures, pas les virgules.
Robert Harvey
1
Je peux très certainement affirmer qu’il n’ya aucune adhésion possible dans les clauses principales. Je pense que vous interprétez de manière incorrecte les constructions de votre requête relationnelle. Avez-vous essayé de joindre votre virgule sans les clauses WHERE? Ça fonctionne encore. C'est une jointure cartésienne. Que pensez-vous gagner en utilisant des virgules? S'il vous plaît ne dites pas que vous essayez de sauver des personnages.
Thomas Stringer
1
Je dirais que le premier est meilleur parce que vos intentions sont plus claires. Il y a beaucoup moins d'ambiguïté.
Daniel Hollinrake le
4

Non, ce n'est pas vrai du tout. L’auteur prépare ses lecteurs à la confusion et encourage une programmation culte du fret qui évite une différence structurelle très forte entre la syntaxe standard et cette variante plus ancienne qu’il préfère. Plus précisément, une clause WHERE encombrée rend plus difficile la compréhension de ce qui rend sa requête si spéciale.

Son exemple conduit un lecteur à générer une carte mentale de sa signification qui a beaucoup d'encombrement.

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

En gros, ce qui précède est:

Obtenez l'identifiant, le nom, l'âge et le mort de l'animal, tous les animaux, la personne et les personnes dont l'identifiant correspond à l'animal, et le id_personne de cette fiche correspond à l'id d'une personne dont le nom FIRST_NAME est "Zed".

Avec une telle carte mentale, le lecteur (qui écrit le code SQL à la main pour une raison quelconque) peut très facilement commettre une erreur, éventuellement en omettant un ou plusieurs tableaux. Et un lecteur de code écrit de cette manière devra travailler plus fort pour comprendre exactement ce que l'auteur de SQL essaie de faire. ("Harder" est au niveau de la lecture SQL avec ou sans mise en surbrillance de la syntaxe, mais la différence est toujours supérieure à zéro.)

Il y a une raison pour laquelle les JOIN sont communs, et c'est le vieux classique "séparation des préoccupations" canard. En particulier, pour une requête SQL, il existe une bonne raison de séparer la structure des données et leur filtrage.

Si la requête est écrite plus propre, telle que

SELECT pet.id, pet.name, pet.age
FROM pet
  JOIN person_pet ON pet.id = person_pet.pet_id
  JOIN person ON person.id = person_pet.person_id
WHERE 
  person.first_name = "Zed";

Ensuite, le lecteur a une distinction plus claire entre les composants de ce qui est demandé. Le filtre distinctif de cette requête est séparé de la façon dont ses composants sont en relation et les composants nécessaires de chaque relation sont directement à côté de l'endroit où ils sont requis.


Bien entendu, aucun système de base de données moderne ne devrait voir une différence significative entre les deux styles. Mais si les performances de la base de données étaient la seule considération, la requête SQL n'aurait pas non plus d'espace blanc ou de majuscule.

DougM
la source
2
Depuis que j'ai entendu ce refrain à plusieurs reprises maintenant, laissez-moi me faire l'avocat du diable. Apprendre X à la dure consiste à avoir de la profondeur technique; quiconque ayant une bonne compréhension de SQL devrait savoir que les deux approches sont équivalentes en termes de sortie.
Robert Harvey
1
Je peux le voir, mais l'auteur n'affirme pas simplement que ce sont des déclarations équivalentes à un serveur SQL décent; ils affirment que l'utilisation de JOIN est "déroutant", c'est-à-dire un chemin vers lequel le code modifié attend. ("Non, n'utilisez pas LINQ, écrivez simplement votre déclaration FOR à la main." "Le compilateur se fiche de ce que j'appelle cette méthode, il n'y a donc aucune raison de ne pas l'appeler FN1")
DougM
3

Guy fait une erreur classique. Il essaie d'enseigner un concept abstrait avec une implémentation spécifique. Dès que vous faites cela, vous vous retrouvez dans ce genre de désordre.

Devrait avoir d'abord enseigné les concepts de base de base de données, puis montré SQL comme une façon de les décrire.

Les jointures gauche et droite pourraient être discutées, elles importent peu. Jointure externe, vous pouvez utiliser l’ancienne *=et la =*syntaxe.

Vous pouvez maintenant dire que la syntaxe est plus simple, mais uniquement pour les requêtes simples. Dès que vous commencez à essayer de faire une requête complexe avec cette version, vous pouvez vous retrouver dans un fouillis horrible. La "nouvelle" syntaxe n'a pas été introduite pour vous permettre de faire des requêtes complexes, mais plutôt pour que vous fassiez des requêtes complexes de manière lisible et donc maintenable.

Tony Hopkinson
la source
3
"Apprendre X à la dure" est une approche d'apprentissage différente. Vous écrivez le code et vous le comprenez plus tard.
Robert Harvey
7
@ RobertHarvey Ce n'est pas une approche d'apprentissage différente, c'est la méthode standard. Plus tard, cela ne se produit que si vous êtes toujours en place lorsque les roues se détachent. Beaucoup trop de gens écrivant en SQL qui pensent qu'une table est un tableau rectangulaire de cellules ont confiance dans cette méthode.
Tony Hopkinson
2

L'exemple équivaut à la reformulation simple avec JOIN internes. La différence réside uniquement dans les possibilités supplémentaires offertes par la syntaxe JOIN. Par exemple, vous pouvez spécifier l'ordre dans lequel les colonnes des deux tables impliquées sont traitées; voir par exemple https://stackoverflow.com/a/1018825/259310 .

La sagesse reçue consiste, en cas de doute, à écrire vos questions de manière à les rendre plus lisibles. Mais, que les formules JOIN ou WHERE soient plus faciles à lire, cela semble être une question de préférence personnelle, ce qui explique pourquoi les deux formes sont si répandues.

Kilian Foth
la source
Bonne réponse, cependant, que vous WHEREutilisiez la clause ou que vous mettiez la clause dans l’ JOINinstruction puisse réellement avoir un impact sur les performances en fonction de l’optimiseur de requêtes. Je l'ai vu arriver plus d'une fois.
Locke
Mon expérience des répercussions sur les performances est la suivante: les jointures implicites donneront à l'optimiseur de requêtes davantage d'options pour optimiser la requête, ce qui peut sembler une bonne chose, mais peut également poser problème. Spécifiquement, l'optimiseur de requête peut ajuster la requête d'une manière en développement et d'une autre en production. L'optimiseur peut être trompé dans un réglage qui réduit les performances. Ma recommandation est d'utiliser une syntaxe de jointure explicite ET de confirmer que la jointure utilise des colonnes avec des index permettant des performances prévisibles.
Michael Potter
2

Quand j'ai appris le SQL, les formulaires INNER JOIN, LEFT JOIN, etc. n'existaient pas. Comme d'autres réponses l'ont déjà indiqué, différents dialectes de SQL ont chacun implémenté des jointures externes utilisant une syntaxe idiosyncratique. Cette portabilité endommagée du code SQL. Rassembler la langue a nécessité quelques changements, et LEFT JOIN, etc., a été choisi.

Il est vrai que pour chaque INNER JOIN, une jointure équivalente avec la condition de jointure de la clause WHERE peut être écrite. Il m'a fallu un certain temps pour migrer d'aimer l'ancien formulaire à préférer le nouveau formulaire. Apparemment, l'auteur de Learning SQL the Hard Way pense toujours que l'ancienne méthode est plus facile.

Y a-t-il des différences? Oui, il y en a. La première est qu'un INNER JOIN avec une clause ON révèle l'intention de l'auteur plus clairement que l'ancien style. Le fait que la clause ON soit en fait une condition de jointure et non un autre type de restriction est plus évident. Cela rend le code utilisant INNER JOIN plus facile à apprendre lors de la lecture que l'ancien style. Ceci est important lors de la maintenance du code de quelqu'un d'autre.

La seconde différence est que le nouveau style permet à l'optimiseur de requêtes de découvrir plus facilement la stratégie gagnante. C'est un très petit effet, mais c'est réel.

La troisième différence est que lorsque vous apprenez à utiliser INNER JOIN (ou simplement plain JOIN), cela facilite l'apprentissage de LEFT JOIN, etc.

En dehors de cela, il n'y a aucune différence matérielle.

Walter Mitty
la source
0

Cela dépend si vous pensez en termes d’ensembles et de logique formelle .....

Si vous n'utilisez pas le mot-clé "join", la progression de la logique formelle vers SQL est simplifiée.

Mais si, comme 99% des personnes, vous n'aimiez pas la logique formelle dans votre diplôme en mathématiques, le mot clé join est un outil plus facile à apprendre. Auparavant, le code SQL était présenté à l’université comme un autre moyen d’écrire des requêtes de logique formelles ....

Ian
la source