Je suis un ancien utilisateur de MySQL et j'ai toujours préféré JOIN
la sous-requête. Mais de nos jours, tout le monde utilise la sous-requête, et je déteste ça; Je ne sais pas pourquoi.
Je n'ai pas les connaissances théoriques pour juger par moi-même s'il y a une différence. Une sous-requête est-elle aussi bonne qu'un JOIN
et donc n'y a-t-il rien à craindre?
Réponses:
Tiré du manuel MySQL ( 13.2.10.11 Réécriture des sous-requêtes en jointures ):
Les sous-requêtes peuvent donc être plus lentes que
LEFT [OUTER] JOIN
, mais à mon avis, leur force est une lisibilité légèrement supérieure.la source
Join
etsub query
a une syntaxe différente, donc la lisibilité nous ne pouvons pas comparer, les deux ont une meilleure lisibilité tant que vous êtes bon en syntaxe SQL. La performance est plus importante.Les sous-requêtes sont le moyen logiquement correct de résoudre les problèmes du formulaire "Obtenir des faits de A, conditionnels aux faits de B". Dans de tels cas, il est plus logique de coller B dans une sous-requête que de faire une jointure. Il est également plus sûr, dans un sens pratique, car vous n'avez pas à être prudent lorsque vous obtenez des faits en double de A en raison de plusieurs correspondances contre B.
En pratique, cependant, la réponse se résume généralement à la performance. Certains optimiseurs aspirent des citrons lorsqu'ils reçoivent une jointure par rapport à une sous-requête, et certains aspirent des citrons dans l'autre sens, et cela est spécifique à l'optimiseur, à la version du SGBD et à la requête.
Historiquement, les jointures explicites gagnent généralement, d'où la sagesse établie selon laquelle les jointures sont meilleures, mais les optimiseurs s'améliorent tout le temps, et je préfère donc écrire les requêtes d'abord de manière logique et cohérente, puis restructurer si les contraintes de performances le justifient.
la source
select custid from cust join bought using (custid) where price > 500
. Si un client a acheté plusieurs articles coûteux, vous obtiendrez des doublons. Pour résoudre ce problème,select custid from cust where exists (select * from bought where custid = cust.custid and price > 500)
. Vous pouvez utiliser à laselect distinct …
place, mais c'est souvent plus de travail, que ce soit pour l'optimiseur ou l'évaluateur.Dans la plupart des cas, les
JOIN
s sont plus rapides que les sous-requêtes et il est très rare qu'une sous-requête soit plus rapide.Dans
JOIN
s, le SGBDR peut créer un plan d'exécution qui convient mieux à votre requête et peut prédire quelles données doivent être chargées pour être traitées et gagner du temps, contrairement à la sous-requête où il exécutera toutes les requêtes et chargera toutes leurs données pour effectuer le traitement. .La bonne chose dans les sous-requêtes est qu'elles sont plus lisibles que
JOIN
s: c'est pourquoi la plupart des nouveaux SQL les préfèrent; c'est la voie facile; mais quand il s'agit de performances, les JOINS sont meilleurs dans la plupart des cas, même s'ils ne sont pas difficiles à lire aussi.la source
select * from a where a.x = (select b.x form b where b.id = a.id)
sont extrêmement petits par rapport à une jointure. C'est un problème très spécifique, mais dans certains cas, cela vous amène de quelques heures à quelques minutes.Utilisez EXPLAIN pour voir comment votre base de données exécute la requête sur vos données. Il y a un énorme "ça dépend" dans cette réponse ...
PostgreSQL peut réécrire une sous-requête dans une jointure ou une jointure dans une sous-requête lorsqu'il pense que l'une est plus rapide que l'autre. Tout dépend des données, des index, de la corrélation, de la quantité de données, de la requête, etc.
la source
En 2010, j'aurais rejoint l'auteur de ces questions et j'aurais fortement voté pour
JOIN
, mais avec beaucoup plus d'expérience (en particulier dans MySQL), je peux dire: Oui, les sous-requêtes peuvent être meilleures. J'ai lu plusieurs réponses ici; certaines sous-requêtes déclarées sont plus rapides, mais il manquait une bonne explication. J'espère pouvoir en fournir une avec cette réponse (très) tardive:Tout d'abord, permettez-moi de dire le plus important: il existe différentes formes de sous-requêtes
Et la deuxième déclaration importante: la taille compte
Si vous utilisez des sous-requêtes, vous devez savoir comment le serveur DB exécute la sous-requête. Surtout si la sous-requête est évaluée une ou pour chaque ligne! D'un autre côté, un DB-Server moderne est capable d'optimiser beaucoup. Dans certains cas, une sous-requête permet d'optimiser une requête, mais une version plus récente du serveur DB peut rendre l'optimisation obsolète.
Sous-requêtes dans Select-Fields
Sachez qu'une sous-requête est exécutée pour chaque ligne résultante de
foo
.Évitez cela si possible; cela peut considérablement ralentir votre requête sur d'énormes ensembles de données. Cependant, si la sous-requête n'a aucune référence,
foo
elle peut être optimisée par le serveur DB en tant que contenu statique et ne peut être évaluée qu'une seule fois.Sous-requêtes dans l'instruction Where
Si vous êtes chanceux, la DB optimise cela en interne en un
JOIN
. Sinon, votre requête deviendra très, très lente sur des ensembles de données énormes car elle exécutera la sous-requête pour chaque lignefoo
, et pas seulement les résultats comme dans le type de sélection.Sous-requêtes dans l'instruction Join
C'est intéressant. Nous combinons
JOIN
avec une sous-requête. Et ici, nous obtenons la véritable force des sous-requêtes. Imaginez un ensemble de données avec des millions de ligneswilco
mais seulement quelques-unes distinctesme
. Au lieu de nous joindre à une immense table, nous avons maintenant une table temporaire plus petite à laquelle nous joindre. Cela peut entraîner des requêtes beaucoup plus rapides en fonction de la taille de la base de données. Vous pouvez avoir le même effet avecCREATE TEMPORARY TABLE ...
etINSERT INTO ... SELECT ...
, ce qui pourrait offrir une meilleure lisibilité sur les requêtes très complexes (mais peut verrouiller les jeux de données dans un niveau d'isolation de lecture répétable).Sous-requêtes imbriquées
Vous pouvez imbriquer des sous-requêtes à plusieurs niveaux. Cela peut vous aider sur d'énormes ensembles de données si vous devez regrouper ou trier les résultats. Habituellement, le serveur DB crée une table temporaire pour cela, mais parfois vous n'avez pas besoin de trier sur la table entière, uniquement sur l'ensemble de résultats. Cela peut fournir des performances bien meilleures en fonction de la taille de la table.
Conclusion
Les sous-requêtes ne remplacent pas a
JOIN
et vous ne devez pas les utiliser comme cela (bien que cela soit possible). À mon humble avis, l'utilisation correcte d'une sous-requête est l'utilisation comme remplacement rapide deCREATE TEMPORARY TABLE ...
. Une bonne sous-requête réduit un ensemble de données d'une manière que vous ne pouvez pas accomplir dans uneON
déclaration de aJOIN
. Si une sous-requête a l'un des mots clésGROUP BY
ouDISTINCT
et n'est de préférence pas située dans les champs de sélection ou dans l'instruction where, cela peut améliorer considérablement les performances.la source
Sub-queries in the Join-statement
: (1) la génération d'une table dérivée à partir de la sous-requête elle-même peut prendre très longtemps. (2) la table dérivée résultante n'est pas indexée. ces deux seuls pourraient ralentir considérablement le SQL.10
enregistrements, car il n'y a pas d'index, cela signifie toujours potentiellement interroger 9 fois plus d'enregistrements de données que sans la table temporaire lorsque vous JOIGNEZ d'autres tables. BTW J'ai eu ce problème auparavant avec ma base de données (MySQL), dans mon cas, l'utilisation de la sous-requête dansSELECT list
pourrait être beaucoup plus rapide.EXPLAIN
une requête avant l'optimisation. Avec l'ancien,set profiling=1
vous pouvez facilement voir si une table temporaire est un goulot d'étranglement. Et même un index a besoin de temps de traitement, les arbres B optimisent l'interrogation des enregistrements, mais une table de 10 enregistrements peut être beaucoup plus rapide qu'un index pour des millions d'enregistrements. Mais cela dépend de plusieurs facteurs comme la taille et le type des champs.Tout d'abord, pour comparer les deux, vous devez distinguer les requêtes avec des sous-requêtes de:
Pour la première classe de requêtes, un bon SGBDR verra les jointures et les sous-requêtes comme équivalentes et produira les mêmes plans de requête.
De nos jours, même mysql fait cela.
Pourtant, parfois ce n'est pas le cas, mais cela ne signifie pas que les jointures gagneront toujours - j'ai eu des cas lors de l'utilisation de sous-requêtes dans mysql performance améliorée. (Par exemple, si quelque chose empêche le planificateur mysql d'estimer correctement le coût et si le planificateur ne voit pas la variante de jointure et la variante de sous-requête comme étant identiques, les sous-requêtes peuvent surpasser les jointures en forçant un certain chemin).
La conclusion est que vous devez tester vos requêtes pour les variantes de jointure et de sous-requête si vous voulez être sûr de celle qui fonctionnera mieux.
Pour la deuxième classe, la comparaison n'a aucun sens car ces requêtes ne peuvent pas être réécrites à l'aide de jointures et dans ces cas, les sous-requêtes sont un moyen naturel d'effectuer les tâches requises et vous ne devez pas les discriminer.
la source
Je pense que ce qui a été sous-souligné dans les réponses citées est la question des doublons et des résultats problématiques qui peuvent résulter de cas (d'utilisation) spécifiques.
(bien que Marcelo Cantos le mentionne)
Je citerai l'exemple des cours Lagunita de Stanford sur SQL.
Table des étudiants
Appliquer la table
(candidatures adressées à des universités et majors spécifiques)
Essayons de trouver les scores GPA pour les étudiants qui ont postulé en
CS
majeure (quelle que soit l'université)Utilisation d'une sous-requête:
La valeur moyenne de cet ensemble de résultats est:
Utilisation d'une jointure:
valeur moyenne pour cet ensemble de résultats:
Il est évident que la deuxième tentative donne des résultats trompeurs dans notre cas d'utilisation, étant donné qu'elle compte les doublons pour le calcul de la valeur moyenne. Il est également évident que l'utilisation de
distinct
l'instruction join-based n'éliminera pas le problème, étant donné qu'elle conservera par erreur une occurrence sur trois du3.9
score. Le cas correct est de prendre en compte DEUX (2) occurrences du3.9
score étant donné que nous avons réellement DEUX (2) étudiants avec ce score qui répondent à nos critères de requête.Il semble que dans certains cas, une sous-requête soit le moyen le plus sûr, en plus de tout problème de performances.
la source
La documentation MSDN pour SQL Server indique
donc si vous avez besoin de quelque chose comme
essayez plutôt d'utiliser join. Dans d'autres cas, cela ne fait aucune différence.
Je dis: Créer des fonctions pour les sous-requêtes élimine le problème du désordre et vous permet d'implémenter une logique supplémentaire aux sous-requêtes. Je recommande donc de créer des fonctions pour les sous-requêtes autant que possible.
L'encombrement du code est un gros problème et l'industrie s'efforce de l'éviter depuis des décennies.
la source
NOT EXISTS
. A l'NOT EXISTS
emporte sur aLEFT OUTER JOIN
pour diverses raisons: performances, sécurité intégrée (en cas de colonnes nulles) et lisibilité. sqlperformance.com/2012/12/t-sql-queries/left-anti-semi-joinExécuter sur une très grande base de données à partir d'un ancien CMS Mambo:
0 secondes
~ 3 secondes
Un EXPLAIN montre qu'ils examinent exactement le même nombre de lignes, mais l'un prend 3 secondes et l'autre est presque instantané. Morale de l'histoire? Si les performances sont importantes (quand n'est-ce pas?), Essayez-les de plusieurs façons et voyez laquelle est la plus rapide.
Et...
0 secondes
Encore une fois, mêmes résultats, même nombre de lignes examinées. Je suppose que DISTINCT mos_content.catid prend beaucoup plus de temps à comprendre que DISTINCT mos_categories.id.
la source
id
et non nommé quelque chose commecatid
? Essayer d'optimiser mes accès db, et vos apprentissages pourraient vous aider.Selon mon observation, comme dans deux cas, si une table a moins de 100 000 enregistrements, la jointure fonctionnera rapidement.
Mais dans le cas où une table a plus de 100 000 enregistrements, une sous-requête est le meilleur résultat.
J'ai une table qui contient 500 000 enregistrements sur lesquels j'ai créé la requête ci-dessous et son temps de résultat est comme
la source
Les sous-requêtes sont généralement utilisées pour renvoyer une seule ligne en tant que valeur atomique, bien qu'elles puissent être utilisées pour comparer des valeurs à plusieurs lignes avec le mot-clé IN. Ils sont autorisés à presque n'importe quel point significatif d'une instruction SQL, y compris la liste cible, la clause WHERE, etc. Une simple sous-requête peut être utilisée comme condition de recherche. Par exemple, entre une paire de tables:
Notez que l'utilisation d'un opérateur de valeur normale sur les résultats d'une sous-requête nécessite qu'un seul champ soit renvoyé. Si vous souhaitez vérifier l'existence d'une seule valeur dans un ensemble d'autres valeurs, utilisez IN:
C'est évidemment différent de dire un LEFT-JOIN où vous voulez simplement joindre des éléments des tables A et B même si la condition de jointure ne trouve aucun enregistrement correspondant dans le tableau B, etc.
Si vous êtes juste inquiet à propos de la vitesse, vous devrez vérifier avec votre base de données et écrire une bonne requête et voir s'il y a une différence significative dans les performances.
la source
Version MySQL: 5.5.28-0ubuntu0.12.04.2-log
J'avais également l'impression que JOIN est toujours meilleur qu'une sous-requête dans MySQL, mais EXPLAIN est un meilleur moyen de porter un jugement. Voici un exemple où les sous-requêtes fonctionnent mieux que les JOIN.
Voici ma requête avec 3 sous-requêtes:
EXPLAIN montre:
La même requête avec JOINs est:
et la sortie est:
Une comparaison des
rows
colonne indique la différence et la requête avec JOIN utiliseUsing temporary; Using filesort
.Bien sûr, lorsque j'exécute les deux requêtes, la première se fait en 0,02 seconde, la seconde ne se termine pas même après 1 minute, alors EXPLAIN a expliqué ces requêtes correctement.
Si je n'ai pas le INNER JOIN sur la
list_tag
table c'est à dire si je retirede la première requête et en conséquence:
à partir de la deuxième requête, puis EXPLAIN renvoie le même nombre de lignes pour les deux requêtes et ces deux requêtes s'exécutent également rapidement.
la source
Les sous-requêtes ont la capacité de calculer des fonctions d'agrégation à la volée. Par exemple, trouvez le prix minimal du livre et obtenez tous les livres qui sont vendus avec ce prix. 1) Utilisation de sous-requêtes:
2) Utilisation de JOINs
la source
GROUP BY
s avec des tables différentes: stackoverflow.com/questions/11415284/… Les sous-requêtes semblent être strictement plus générales. Voir aussi l'homme MySQL: dev.mysql.com/doc/refman/5.7/en/optimizing-subqueries.html | dev.mysql.com/doc/refman/5.7/en/rewriting-subqueries.htmlCertaines personnes disent que "certains SGBDR peuvent réécrire une sous - requête dans une jointure ou une jointure dans une sous - requête quand ils pensent que l'un est plus rapide que l'autre.", Mais cette déclaration s'applique aux cas simples, certainement pas pour les requêtes compliquées avec des sous-requêtes qui provoquent réellement un problèmes de performances.
la source
La différence n'est visible que lorsque la deuxième table de jointure contient beaucoup plus de données que la table principale. J'ai eu une expérience comme ci-dessous ...
Nous avions un tableau d'utilisateurs de cent mille entrées et leurs données d'adhésion (amitié) environ 3 cent mille entrées. C'était une déclaration de jointure afin de prendre des amis et leurs données, mais avec beaucoup de retard. Mais cela fonctionnait bien là où il n'y avait qu'une petite quantité de données dans le tableau des membres. Une fois que nous l'avons modifié pour utiliser une sous-requête, cela a bien fonctionné.
Mais en attendant, les requêtes de jointure fonctionnent avec d'autres tables qui ont moins d'entrées que la table principale.
Je pense donc que les instructions de jointure et de sous-requête fonctionnent correctement et cela dépend des données et de la situation.
la source
De nos jours, de nombreux dbs peuvent optimiser les sous-requêtes et les jointures. Ainsi, vous devez simplement examiner votre requête en utilisant Explain et voir laquelle est la plus rapide. S'il n'y a pas beaucoup de différence de performances, je préfère utiliser la sous-requête car elles sont simples et plus faciles à comprendre.
la source
Je pense juste au même problème, mais j'utilise la sous-requête dans la partie FROM. J'ai besoin de me connecter et d'interroger à partir de grandes tables, la table "esclave" a un record de 28 millions mais le résultat n'est que de 128 données si petites que le big data! J'utilise la fonction MAX () dessus.
D'abord, j'utilise LEFT JOIN parce que je pense que c'est la bonne façon, le mysql peut être optimisé, etc. Deuxième fois juste pour les tests, je réécris pour sous-sélectionner contre JOIN.
LEFT JOIN runtime: 1.12s SUB-SELECT runtime: 0.06s
La sous-sélection 18 fois plus rapide que la jointure! Juste dans le chokito adv. La sous-sélection a l'air terrible mais le résultat ...
la source
Si vous souhaitez accélérer votre requête à l'aide de la jointure:
Pour "jointure interne / jointure", n'utilisez pas la condition where à la place, utilisez-la dans la condition "ON". Par exemple:
Pour "Jointure gauche / droite", ne pas utiliser en condition "ON", car si vous utilisez la jointure gauche / droite, il obtiendra toutes les lignes pour une même table. Donc, essayez d'utiliser la condition "Où"
la source