Y at-il quelque chose de mal avec les jointures qui n'utilisent pas le mot clé JOIN dans SQL ou MySQL?

StackOverflow https://stackoverflow.com/questions/128965

  •  02-07-2019
  •  | 
  •  

Question

Lorsque j'ai commencé à écrire des requêtes dans la base de données, je ne connaissais pas encore le mot-clé JOIN et, naturellement, j'ai simplement étendu ce que je savais déjà et écrit des requêtes comme celle-ci:

SELECT a.someRow, b.someRow 
FROM tableA AS a, tableB AS b 
WHERE a.ID=b.ID AND b.ID= $someVar

Maintenant que je sais que c'est la même chose qu'un INNER JOIN, je trouve toutes ces requêtes dans mon code et je me demande si je devrais les réécrire. Y at-il une odeur ou une odeur chez eux?

EDIT:

Résumé de ma réponse : cette requête n'a rien d'anormal, MAIS l'utilisation des mots clés rendra probablement le code plus lisible / maintenable.

Ma conclusion : je ne changerai pas mes anciennes requêtes mais je corrigerai mon style d'écriture et utiliserai les mots clés à l'avenir.

MERCI pour vos réponses!

Était-ce utile?

La solution

Filtrer les jointures uniquement à l'aide de WHERE peut s'avérer extrêmement inefficace dans certains scénarios courants. Par exemple:

SELECT * FROM people p, companies c 
    WHERE p.companyID = c.id AND p.firstName = 'Daniel'

La plupart des bases de données exécuteront cette requête littéralement, en prenant d'abord le produit cartésien du tables de personnes et sociétés et filtrage puis par celles dont les champs companyID et id correspondent. Alors que le produit totalement non contraint n’existe nulle part en mémoire, il ne prend que quelques instants, mais son calcul prend un certain temps.

Une meilleure approche consiste à regrouper les contraintes avec les éléments JOIN , le cas échéant. Ce n'est pas seulement subjectivement plus facile à lire, mais aussi beaucoup plus efficace. Ainsi:

SELECT * FROM people p JOIN companies c ON p.companyID = c.id
    WHERE p.firstName = 'Daniel'

C'est un peu plus long, mais la base de données peut consulter la clause ON et l'utiliser pour calculer directement le JOIN entièrement contraint, plutôt que de commencer par < em> tout et ensuite limiter. C’est plus rapide à calculer (surtout avec les grands ensembles de données et / ou les jointures entre plusieurs tables) et nécessite moins de mémoire.

Je modifie toutes les requêtes que je vois qui utilisent la "virgule JOIN ". syntaxe. À mon avis, le seul but de son existence est la concision. Compte tenu de l'impact sur les performances, je ne pense pas que ce soit une raison impérieuse.

Autres conseils

Les éléments INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN , plus détaillés, proviennent de la syntaxe ANSI SQL / 92 pour la jonction. Pour moi, cette verbosité rend la jointure plus claire pour le développeur / DBA de l’intention de la jointure.

Dans SQL Server, il existe toujours des plans de requête à vérifier, une sortie texte peut être créée comme suit:

SET SHOWPLAN_ALL ON
GO

DECLARE @TABLE_A TABLE
(
    ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    Data VARCHAR(10) NOT NULL
)
INSERT INTO @TABLE_A
SELECT 'ABC' UNION 
SELECT 'DEF' UNION
SELECT 'GHI' UNION
SELECT 'JKL' 

DECLARE @TABLE_B TABLE
(
    ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    Data VARCHAR(10) NOT NULL
)
INSERT INTO @TABLE_B
SELECT 'ABC' UNION 
SELECT 'DEF' UNION
SELECT 'GHI' UNION
SELECT 'JKL' 

SELECT A.Data, B.Data
FROM
    @TABLE_A AS A, @TABLE_B AS B
WHERE
    A.ID = B.ID

SELECT A.Data, B.Data
FROM
    @TABLE_A AS A
    INNER JOIN @TABLE_B AS B ON A.ID = B.ID

Maintenant, je vais omettre le plan pour la variable de table crée, le plan pour les deux requêtes est identique, cependant:

 SELECT A.Data, B.Data  FROM   @TABLE_A AS A, @TABLE_B AS B  WHERE   A.ID = B.ID
  |--Nested Loops(Inner Join, OUTER REFERENCES:([A].[ID]))
       |--Clustered Index Scan(OBJECT:(@TABLE_A AS [A]))
       |--Clustered Index Seek(OBJECT:(@TABLE_B AS [B]), SEEK:([B].[ID]=@TABLE_A.[ID] as [A].[ID]) ORDERED FORWARD)
 SELECT A.Data, B.Data  FROM   @TABLE_A AS A   INNER JOIN @TABLE_B AS B ON A.ID = B.ID
  |--Nested Loops(Inner Join, OUTER REFERENCES:([A].[ID]))
       |--Clustered Index Scan(OBJECT:(@TABLE_A AS [A]))
       |--Clustered Index Seek(OBJECT:(@TABLE_B AS [B]), SEEK:([B].[ID]=@TABLE_A.[ID] as [A].[ID]) ORDERED FORWARD)

Donc, réponse courte: vous n'avez pas besoin de réécrire, à moins que vous passiez beaucoup de temps à essayer de les lire chaque fois que vous les maintenez?

C'est plus un choix de syntaxe. Je préfère regrouper mes conditions de jointure avec mes jointures; par conséquent, j'utilise la syntaxe INNER JOIN

.
SELECT a.someRow, b.someRow
FROM tableA AS a
INNER JOIN tableB AS b
  ON a.ID = b.ID
WHERE b.ID = ?

(? étant un espace réservé)

La syntaxe de votre exemple n’est pas fausse. La syntaxe 'INNER JOIN' est généralement appelée syntaxe 'ANSI' et vient après le style illustré dans votre exemple. Il existe pour clarifier le type / direction / constituants de la jointure, mais n’est généralement pas différent de ce que vous avez fonctionnellement.

La prise en charge des jointures 'ANSI' est une plate-forme par base de données, mais elle est plus ou moins universelle de nos jours.

En note de bas de page, l'un des ajouts avec la syntaxe 'ANSI' était 'FULL OUTER JOIN' ou 'FULL JOIN'.

J'espère que cela vous aidera.

En général:

Utilisez le mot-clé JOIN pour lier (c.-à-d. "joindre") des clés primaires et des clés étrangères.

Utilisez la clause WHERE pour limiter votre jeu de résultats aux enregistrements qui vous intéressent.

Le seul problème qui peut se poser concerne le mélange de l'ancien " style virgule " joindre avec SQL-92 jointes dans la même requête, par exemple si vous avez besoin d'une jointure interne et d'une autre jointure externe.

SELECT *
FROM table1 AS a, table2 AS b
 LEFT OUTER JOIN table3 AS c ON a.column1 = c.column1
WHERE a.column2 = b.column2;

Le problème est que les normes SQL récentes disent que la jointure est évaluée avant la jointure par virgule. Ainsi, la référence à " a " dans la clause ON donne une erreur, car le nom de corrélation n'a pas encore été défini car cette clause ON est en cours d'évaluation. C'est une erreur très confuse à obtenir.

La solution consiste à ne pas mélanger les deux styles de jointure. Vous pouvez continuer à utiliser le style virgule dans votre ancien code, mais si vous écrivez une nouvelle requête, convertissez toutes les jointures en style SQL-92.

SELECT *
FROM table1 AS a
 INNER JOIN table2 AS b ON a.column2 = b.column2
 LEFT OUTER JOIN table3 AS c ON a.column1 = c.column1;

Une autre chose à considérer dans l'ancienne syntaxe de jointure est qu'il est très facile d'obtenir une jointure cartesion par accident puisqu'il n'y a pas de clause on. Si le mot clé Distinct se trouve dans la requête et qu'il utilise les jointures à l'ancien style, convertissez-le en jointure standard ANSI et vérifiez si vous avez toujours besoin de la distinction. Si vous corrigez des jointures accidentelles de cette façon, vous pouvez améliorer considérablement les performances en réécrivant pour spécifier les champs de jointure et de jointure.

J'évite les jointures implicites; quand la requête est vraiment grosse, ils rendent le code difficile à déchiffrer

Avec des jointures explicites et une bonne mise en forme, le code est plus lisible et compréhensible sans qu'il soit nécessaire de commenter.

Cela dépend également de savoir si vous faites uniquement des jointures internes de cette façon ou des jointures externes. Par exemple, la syntaxe MS SQL Server pour les jointures externes dans la clause WHERE (= * et * =) peut donner des résultats différents de ceux de la syntaxe OUTER JOIN et n'est plus prise en charge ( http://msdn.microsoft.com/en-us/library/ms178653 (SQL.90) .aspx ) dans SQL Server 2005.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top