web-dev-qa-db-fra.com

Les requêtes ANSI JOIN et non-ANSI JOIN fonctionneront-elles différemment?

J'ai ma logique métier dans environ 7000 lignes de procédures stockées T-SQL, et la plupart d'entre elles ont la syntaxe JOIN suivante:

SELECT A.A, B.B, C.C
FROM aaa AS A, bbb AS B, ccc AS C
WHERE
    A.B = B.ID
AND B.C = C.ID
AND C.ID = @param

Vais-je obtenir une croissance des performances si je remplace une telle requête par ceci:

SELECT A.A, B.B, C.C
FROM aaa AS A
JOIN bbb AS B
   ON A.B = B.ID
JOIN ccc AS C
   ON B.C = C.ID
   AND C.ID = @param

Ou ce sont les mêmes?

55
abatishchev

Les deux requêtes sont identiques, sauf que la seconde est la syntaxe SQL ANSI-92 et la première est l'ancienne syntaxe SQL qui n'incorporait pas la clause join. Ils devraient produire exactement le même plan de requête interne, bien que vous souhaitiez peut-être vérifier.

Vous devez utiliser la syntaxe ANSI-92 pour plusieurs raisons

  • L'utilisation de la clause JOIN sépare la logique de relation de la logique de filtrage (WHERE) et est donc plus propre et plus facile à comprendre.
  • Cela n'a pas d'importance avec cette requête particulière, mais dans certaines circonstances, l'ancienne syntaxe de jointure externe (à l'aide de +) est ambiguë et les résultats de la requête dépendent donc de l'implémentation - ou la requête ne peut pas être résolue du tout. Cela ne se produit pas avec ANSI-92
  • C'est une bonne pratique car la plupart des développeurs et des dba utiliseront ANSI-92 de nos jours et vous devriez suivre la norme. Certes, tous les outils de requête modernes généreront ANSI-92.
  • Comme l'a souligné @gbn, il a tendance à éviter les jointures croisées accidentelles.

Moi-même j'ai résisté à ANSI-92 pendant un certain temps car il y a un léger avantage conceptuel à l'ancienne syntaxe car il est plus facile d'envisager le SQL comme une jointure cartésienne de masse de toutes les tables utilisées suivie d'une opération de filtrage - une technique mentale qui peut être utile pour comprendre ce que fait une requête SQL. Cependant, j'ai décidé il y a quelques années que je devais évoluer avec le temps et après une période d'ajustement relativement courte, je la préfère fortement - principalement pour la première raison donnée ci-dessus. Le seul endroit où l'on devrait s'écarter de la syntaxe ANSI-92, ou plutôt ne pas utiliser l'option, est avec les jointures naturelles qui sont implicitement dangereuses.

75
Cruachan

La deuxième construction est connue sous le nom de "syntaxe de jointure infixée" dans la communauté SQL. La première construction AFAIK n'a pas de nom largement accepté, appelons-la la syntaxe de jointure interne "à l'ancienne".

Les arguments habituels vont comme ceci:

Avantages de la syntaxe "traditionnelle": les prédicats sont physiquement regroupés dans la clause WHERE dans l'ordre qui rend la requête en général, et les relations n-aires en particulier, plus faciles à lire et à comprendre (le ON les clauses de la syntaxe infixée peuvent étaler les prédicats, vous devez donc rechercher l'apparence d'une table ou d'une colonne sur une distance visuelle).

Inconvénients de la syntaxe "traditionnelle": il n'y a pas d'erreur d'analyse lors de l'omission d'un des prédicats "join" et le résultat est un produit cartésien (connu sous le nom de CROSS JOIN dans la syntaxe infixée) et une telle erreur peut être difficile à détecter et à déboguer. De plus, les prédicats de "jointure" et de "filtrage" sont physiquement regroupés dans la clause WHERE, ce qui peut les amener à se confondre.

4
onedaywhen

OK, ils exécutent la même chose. C'est d'accord. Contrairement à beaucoup, j'utilise l'ancienne convention. Que SQL-92 soit "plus facile à comprendre" est discutable. Ayant écrit des langages de programmation pour pousser 40 ans (gulp), je sais que `` facile à lire '' commence d'abord, avant toute autre convention, par `` acuité visuelle '' (terme mal appliqué ici mais c'est la meilleure phrase que je puisse utiliser). Lors de la lecture de SQL, la PREMIÈRE chose à laquelle vous vous souciez est de savoir quelles tables sont impliquées, puis quelle table (la plupart) définit le grain. Ensuite, vous vous souciez des contraintes pertinentes sur les données, puis des attributs sélectionnés. Alors que SQL-92 sépare principalement ces idées, il y a tellement de mots parasites, l'œil de l'esprit doit les interpréter et les traiter et cela rend la lecture du SQL plus lente.

SELECT Mgt.attrib_a   AS attrib_a
      ,Sta.attrib_b   AS attrib_b
      ,Stb.attrib_c   AS attrib_c
FROM   Main_Grain_Table  Mgt
      ,Surrounding_TabA  Sta
      ,Surrounding_tabB  Stb
WHERE  Mgt.sta_join_col  = Sta.sta_join_col
AND    Mgt.stb_join_col  = Stb.stb_join_col
AND    Mgt.bus_logic_col = 'TIGHT'

Acuité visuelle! Mettez les virgules pour les nouveaux attributs à l'avant Cela facilite également le commentaire du code Utilisez un cas spécifique pour les fonctions et les mots clés Utilisez un cas spécifique pour les tableaux Utilisez un cas spécifique pour les attributs Alignez verticalement les opérateurs et les opérations Créez les premières tables du FROM représenter le grain des données Faites les premières tables des contraintes de jointure WHERE be et laissez les contraintes spécifiques et serrées flotter vers le bas. Sélectionnez un alias de 3 caractères pour TOUTES les tables de votre base de données et utilisez l'alias PARTOUT où vous référencez la table. Vous devez également utiliser cet alias comme préfixe pour (de nombreux) index sur cette table. 6 sur 1 1/2 douzaine d'un autre, non? Peut être. Mais même si vous utilisez la convention ANSI-92 (comme je l'ai fait et dans certains cas continuerons à le faire), utilisez les principes d'acuité visuelle, l'alignement des verticules pour permettre à votre esprit de se détourner des endroits que vous voulez voir et d'éviter facilement les choses (en particulier mots de bruit) vous n'avez pas besoin.

4
TwoEdgedSword

Exécutez les deux et vérifiez leurs plans de requête. Ils devraient être égaux.

3
sisve

Les deux requêtes sont égales - la première utilise la syntaxe JOIN non ANSI, la seconde est la syntaxe JOIN ANSI. Je recommande de s'en tenir à la syntaxe ANSI JOIN.

Et oui, LEFT OUTER JOINs (qui, btw est également la syntaxe ANSI JOIN) est ce que vous souhaitez utiliser lorsqu'il est possible que la table à laquelle vous vous joignez ne contienne aucun enregistrement correspondant.

Référence: jointures conditionnelles dans SQL Server

3
OMG Ponies

Dans mon esprit, la clause FROM est l'endroit où je décide des colonnes dont j'ai besoin dans les lignes sur lesquelles ma clause SELECT doit fonctionner. C'est là où une règle métier est exprimée qui apportera sur la même ligne, les valeurs nécessaires aux calculs. La règle commerciale peut être des clients qui ont des factures, ce qui entraîne des lignes de factures incluant le client responsable. Il peut également s'agir de sites dans le même code postal que les clients, ce qui donne une liste de sites et de clients proches.

C'est là que je détermine la centricité des lignes dans mon jeu de résultats. Après tout, on nous montre simplement la métaphore d'une liste dans les SGBDR, chaque liste ayant un sujet (l'entité) et chaque ligne étant une instance de l'entité. Si la centricité des lignes est comprise, l'entité de l'ensemble de résultats est comprise.

La clause WHERE, qui s'exécute conceptuellement après la définition des lignes dans la clause from, supprime les lignes non requises (ou inclut les lignes requises) pour que la clause SELECT fonctionne.

Parce que la logique de jointure peut être exprimée à la fois dans la clause FROM et dans la clause WHERE, et parce que les clauses existent pour diviser et conquérir une logique complexe, j'ai choisi de mettre une logique de jointure qui implique des valeurs dans les colonnes de la clause FROM, car cela exprime essentiellement une entreprise règle prise en charge par la correspondance des valeurs dans les colonnes.

c'est-à-dire que je n'écrirai pas de clause WHERE comme celle-ci:

 WHERE Column1 = Column2

Je mettrai cela dans la clause FROM comme ceci:

 ON Column1 = Column2

De même, si une colonne doit être comparée à des valeurs externes (valeurs qui peuvent ou non être dans une colonne) telles que la comparaison d'un code postal à un code postal spécifique, je mettrai cela dans la clause WHERE parce que je dis essentiellement que je veux seulement des lignes comme celle-ci.

c'est-à-dire que je n'écrirai pas une clause FROM comme ceci:

 ON PostCode = '1234'

Je mettrai cela dans la clause WHERE comme ceci:

 WHERE PostCode = '1234'
1
John

La syntaxe ANSI n'applique ni le placement des prédicats dans la clause appropriée (que ce soit ON ou WHERE), ni l'affinité de la clause ON avec la référence de table adjacente. Un développeur est libre d'écrire un gâchis comme celui-ci

SELECT
   C.FullName,
   C.CustomerCode,
   O.OrderDate,
   O.OrderTotal,
   OD.ExtendedShippingNotes
FROM
   Customer C
   CROSS JOIN Order O
   INNER JOIN OrderDetail OD
      ON C.CustomerID = O.CustomerID
      AND C.CustomerStatus = 'Preferred'
      AND O.OrderTotal > 1000.0
WHERE
   O.OrderID = OD.OrderID;

En parlant des outils de requête qui "généreront ANSI-92", je commente ici car il a généré

SELECT 1
   FROM DEPARTMENTS C
        JOIN EMPLOYEES A
             JOIN JOBS B
     ON C.DEPARTMENT_ID = A.DEPARTMENT_ID
     ON A.JOB_ID = B.JOB_ID

La seule syntaxe qui échappe au conventionnel "restrict-project-cartésian product" est la jointure externe. Cette opération est plus compliquée car elle n'est pas associative (à la fois avec elle-même et avec la jointure normale). Il faut au moins judicieusement mettre entre parenthèses la requête avec la jointure externe. Cependant, c'est une opération exotique; si vous l'utilisez trop souvent, je suggère de prendre une classe de base de données relationnelle.

0
Tegiri Nenashi