web-dev-qa-db-fra.com

Un JOIN est-il plus rapide qu'un WHERE?

Supposons que j'ai deux tables liées (l'une a une clé étrangère à l'autre):

CREATE TABLE Document (
  Id INT PRIMARY KEY,
  Name VARCHAR 255
)

CREATE TABLE DocumentStats (
  Id INT PRIMARY KEY,
  DocumentId INT, -- this is a foreign key to table Document
  NbViews INT
)

Je sais, ce n'est pas la façon la plus intelligente de faire les choses, mais c'est le meilleur exemple que j'ai pu trouver.

Maintenant, je veux obtenir tous les documents qui ont plus de 500 vues. Les deux solutions qui me viennent à l'esprit sont:

SELECT *
FROM Document, DocumentStats
WHERE DocumentStats.Id = Document.Id
  AND DocumentStats.NbViews > 500

ou :

SELECT *
FROM Document
INNER JOIN DocumentStats
ON Document.Id = DocumentStats.Id
WHERE DocumentStats.NbViews > 500

Les deux requêtes sont-elles équivalentes ou existe-t-il une manière bien meilleure que l'autre? Si oui, pourquoi ?

Je suis conscient que mon exemple n'est pas parfait et que les requêtes peuvent nécessiter une mise au point, mais j'espère que vous avez compris;)!

EDIT: comme demandé dans les réponses, cette question s'adressait à MSSQL, mais je serais intéressé de savoir si c'est différent pour les autres moteurs DB (MySQL, etc ...)

54
Wookai

Théoriquement, non, ça ne devrait pas être plus rapide. L'optimiseur de requêtes doit pouvoir générer un plan d'exécution identique. Cependant, certains moteurs de base de données peuvent produire de meilleurs plans d'exécution pour l'un d'entre eux (peu susceptible de se produire pour une requête aussi simple mais pour des requêtes suffisamment complexes). Vous devriez tester les deux et voir (sur votre moteur DB).

43
Mehrdad Afshari

Performance de "JOIN" par rapport à "WHERE" ... tout dépend de la capacité du moteur de base de données à optimiser la requête pour vous. Il prendra en compte tous les index que vous pourriez avoir sur les colonnes renvoyées et considérera que les performances des clauses WHERE et JOIN dépendent également du fichier de base de données physique lui-même et de son niveau de fragmentation et même de la technologie de stockage que vous utilisez pour stocker les fichiers de base de données sur .

Le serveur MSSql exécute les requêtes dans l'ordre suivant (cela devrait vous donner une idée des fonctions des clauses WHERE et JOIN)

Ordre de processus de requête Microsoft SQL Server

ce qui suit est tiré de l'excellente série de livres sur Microsoft SQL Server, Dans Microsoft SQL Server 2005: Requête T-SQL qui peut être trouvée ici

(Étape 8) SELECT (Étape 9) DISTINCT (Étape 11)
(Étape 1) FROM left_table
(Étape 3) join_type JOIN right_table
(Étape 2) ON join_condition
(Étape 4) OERE where_condition
(Étape 5) GROUP BY group_by_list
(Étape 6) AVEC [CUBE | ROLLUP]
(Étape 7) AYANT ayant_clause
(Étape 10) COMMANDEZ PAR order_by_list

17
Mike J

Il n'y a aucun moyen de répondre correctement à cela sans se limiter à une base de données cible.

Pour MS-SQL, les deux requêtes aboutissent aux mêmes plans d'exécution, mais gardez à l'esprit:

SELECT *
FROM Document, DocumentStats
WHERE DocumentStats.Id = Document.Id
  AND DocumentStats.NbViews > 500

Est vraiment risqué car il est facile d'oublier la condition de jointure dans la clause WHERE et de se retrouver avec une jointure croisée méchante.

12
Sam Saffron

Dans MySQL au moins, ils seront tous deux optimisés pour la même requête.

4
Greg

Les jointures explicites sont plus faciles à maintenir car l'intention de la requête est beaucoup plus claire. De plus, ils ne sont pas soumis à des jointures croisées accidentelles, donc si vous avez une jointure croisée dans la requête, le responsable sait qu'elle était censée être là.

Si vous devez utiliser des jointures externes, vous devez savoir que la syntaxe * = est déconseillée dans SQL Server et sera bientôt supprimée. De plus, il ne fonctionne pas actuellement comme prévu tout le temps et peut ne pas donner de résultats corrects et ne doit donc JAMAIS être utilisé. Le mélange de jointures externes explicites et de jointures de clause where (jointures implicites) rend la requête beaucoup plus difficile à lire et à comprendre pour un responsable.

2
HLGEM

Si vous parlez spécifiquement de SQL Server, vous devez certainement utiliser la syntaxe INNER JOIN. En plus d'être (alerte d'opinion personnelle!) Plus facile à lire et plus claire dans son intention, il n'y a pas, depuis SQL Server 2005, de syntaxe équivalente pour les jointures externes. La syntaxe * = et = * n'est pas prise en charge par défaut en 2005 - vous devez activer un mode de compatibilité pour la prendre en charge. Il sera éventuellement supprimé, peut-être dès la prochaine version (ou peut-être pas!)

Ça signifie:

  • Si vous devez changer une requête de jointure interne en jointure externe, vous devez la réécrire (argh) ou activer le mode compat (yuk)
  • Sans mode compat, vous ne pouvez pas être cohérent avec la façon dont vous implémentez différents types de jointures (internes vs externes), ce qui crée un cauchemar de maintenance (et, lorsque les deux sont combinés dans la même requête, un comportement non intuitif).

Notez également que contrairement à la croyance populaire, les deux sont pas équivalents. Certaines choses sont beaucoup plus délicates et d'autres sont tout simplement impossibles. Kalen Delaney's Inside SQL Server 20 couvre quelques exemples; Je ne sais pas si les nouvelles éditions le font, car cette syntaxe de jointure est de toute façon obsolète.

2
Cowan

Il est "standard" d'utiliser la syntaxe INNER JOIN, bien que pratiquement équivalente. La raison principale pour laquelle il doit être utilisé est à des fins de clarté et de mobilité car il est cohérent avec la syntaxe OUTER JOIN.

2
Sev

Lorsque vous utilisez Sqlite: La syntaxe where est légèrement plus rapide car Sqlite traduit d'abord la syntaxe de jointure en la syntaxe where avant d'exécuter la requête.

2
Theo

Je suppose que cela ne fait pas de différence non plus. Pour être sûr, vous pouvez vérifier si le plan d'explication de ces deux requêtes est identique. Afin de regarder le plan d'explication dans MySQL, vous devez mettre le mot-clé "expliquer" avant l'instruction, par exemple:

EXPLAIN
SELECT *
FROM Document, DocumentStats
WHERE DocumentStats.Id = Document.Id
  AND DocumentStats.NbViews > 500

Je suis sûr qu'il existe également un équivalent dans MSSQL.

Soit dit en passant: cela ressemble à une relation 1: 1, je voudrais donc simplement inclure l'attribut nbviews directement dans la table de document, vous pouvez donc enregistrer une jointure.

1
samson

Dans MSSQL, les deux requêtes sont compilées dans le même plan d'exécution, il n'y a donc pas de différence. Il s'agit plus de lisibilité - je pense que le JOIN est plus facile à lire, donc je l'utilise.

1
SqlRyan