Je suis un utilisateur MySQL de la vieille école 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 la déteste; Je ne sais pas pourquoi.
Il me manque les connaissances théoriques pour juger par moi-même s'il y a une différence. Une sous-requête vaut-elle aussi une JOIN
et n’y at-il donc rien à craindre?
Extrait du manuel MySQL ( 13.2.10.11 Réécriture des sous-requêtes en jointures ):
Une jointure gauche [OUTER] JOIN peut être plus rapide qu'une sous-requête équivalente car le serveur pourrait mieux l'optimiser, ce qui n'est pas spécifique au serveur MySQL.
Donc, les sous-requêtes peuvent être plus lentes que LEFT [OUTER] JOINS, mais à mon avis, leur force est d'une lisibilité légèrement supérieure.
Les sous-requêtes sont le moyen logiquement correct de résoudre les problèmes de la forme "Obtenir des faits de A, conditionnés par des faits de B". Dans de tels cas, il est plus logique de coller B dans une sous-requête que de faire une jointure. C'est également plus sûr, sur le plan pratique, car il n'est pas nécessaire d'être prudent pour obtenir des doublons de A en raison de plusieurs matchs contre B.
En pratique, cependant, la réponse est généralement liée à la performance. Certains optimiseurs sucent des citrons lorsqu'on leur donne une jointure par rapport à une sous-requête, tandis que d'autres sucent des citrons de l'autre, et ceci est spécifique à l'optimiseur, à la version du SGBD et à la requête.
Historiquement, les jointures explicites sont généralement gagnantes, d’où la sagesse bien établie selon laquelle les jointures sont meilleures, mais les optimiseurs s’améliorent constamment. Je préfère donc écrire des requêtes de manière cohérente et logique, puis les restructurer si les contraintes de performances le justifient.
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 mieux adapté à votre requête et prévoir les données à charger pour le traitement et gagner du temps, contrairement à la sous-requête dans laquelle toutes les requêtes sont exécutées et toutes les données chargées du 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 utilisateurs de SQL les préfèrent; c'est le moyen facile; mais quand il s'agit de performance, JOINS est meilleur dans la plupart des cas, même s’ils ne sont pas difficiles à lire aussi.
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 sur une jointure ou une jointure sur une sous-requête quand 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.
Tout d'abord, pour comparer les deux premiers, vous devez distinguer les requêtes avec des sous-requêtes en:
Pour la première classe des requêtes, un bon SGBDR considère les jointures et les sous-requêtes comme équivalentes et produit les mêmes plans de requête.
De nos jours, même MySQL le fait.
Pourtant, parfois, ce n'est pas le cas, mais cela ne signifie pas que les jointures seront toujours gagnantes. J'avais des cas d'utilisation de sous-requêtes dans les performances améliorées de MySQL. (Par exemple, si quelque chose empêche le planificateur mysql d'estimer correctement le coût et si le planificateur ne voit pas les variantes de jointure et de sous-requête comme identiques, les sous-requêtes peuvent surperformer 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 savoir laquelle fonctionnera le 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. Dans ce cas, les sous-requêtes constituent un moyen naturel d'exécuter les tâches requises et vous ne devez pas les discriminer.
En 2010, j'aurais rejoint l'auteur de cette question et aurais fortement voté pour JOIN
. Mais avec beaucoup plus d'expérience (en particulier dans MySQL), je peux affirmer: Oui, les sous-requêtes peuvent être meilleures. J'ai lu plusieurs réponses ici. Certains ont déclaré que les sous-requêtes sont plus rapides, mais il manquait une bonne explication. J'espère que je pourrai fournir à cette réponse (très) tardive:
Tout d’abord, laissez-moi 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 de base de données exécute la sous-requête. Surtout si la sous-requête est évaluée une fois ou toutes les lignes!!. De l'autre côté, un serveur de base de données 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 de base de données peut rendre l'optimisation obsolète.
SELECT moo, (SELECT roger FROM wilco WHERE moo = me) AS bar FROM foo
Sachez qu'une sous-requête est exécutée pour chaque ligne résultante de foo
. Évitez cela si possible, cela pourrait ralentir considérablement votre requête sur des jeux de données volumineux. Toutefois, si la sous-requête ne contient aucune référence à foo
, elle peut être optimisée par le serveur de base de données en tant que contenu statique et ne peut être évaluée qu'une seule fois.
SELECT moo FROM foo WHERE bar = (SELECT roger FROM wilco WHERE moo = me)
Si vous avez de la chance, la base de données l’optimise en interne dans une variable JOIN
. Sinon, votre requête deviendra très très lente sur des jeux de données volumineux, car elle exécutera la sous-requête pour chaque ligne dans foo
, et pas seulement les résultats comme dans le type-type.
SELECT moo, bar
FROM foo
LEFT JOIN (
SELECT MIN(bar), me FROM wilco GROUP BY me
) ON moo = me
C'est intéressant. Nous combinons JOIN
avec une sous-requête. Et nous obtenons ici la force réelle des sous-requêtes. Imaginez un ensemble de données avec des millions de lignes dans wilco
mais seulement quelques me
distincts. Au lieu de rejoindre une table immense, nous avons maintenant une table temporaire plus petite. 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 avec CREATE TEMPORARY TABLE ...
et INSERT INTO ... SELECT ...
, qui pourraient fournir une meilleure lisibilité pour les requêtes très complexes (mais peuvent verrouiller les jeux de données dans un niveau d'isolation en lecture répétable).
SELECT moo, bar
FROM (
SELECT moo, CONCAT(roger, wilco) AS bar
FROM foo
GROUP BY moo
HAVING bar LIKE 'SpaceQ%'
) AS temp_foo
GROUP BY bar
ORDER BY bar
Vous pouvez imbriquer des sous-requêtes dans plusieurs niveaux. Cela peut aider sur d’énormes jeux de données, si vous devez regrouper ou trier les résultats. En règle générale, le serveur de base de données crée une table temporaire à cet effet, mais vous n'avez parfois pas besoin de trier l'ensemble de la table, mais uniquement le jeu de résultats. Cela pourrait fournir de bien meilleures performances en fonction de la taille de la table.
Les sous-requêtes ne remplacent pas une JOIN
et vous ne devriez pas les utiliser comme ceci (bien que possible). À mon humble avis, l’utilisation correcte d’une sous-requête est l’utilisation en remplacement rapide de CREATE 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 une instruction ON
d'une JOIN
. Si une sous-requête comporte l'un des mots clés GROUP BY
ou DISTINCT
et qu'elle ne se trouve de préférence pas dans les champs de sélection ou dans l'instruction where, elle peut améliorer considérablement les performances.
La documentation MSDN pour SQL Server indique
De nombreuses instructions Transact-SQL comprenant des sous-requêtes peuvent également être formulées en jointures. D'autres questions ne peuvent être posées qu'avec des sous-requêtes. Dans Transact-SQL, il n'y a généralement pas de différence de performances entre une instruction qui inclut une sous-requête et une version sémantiquement équivalente qui n'en contient pas. Cependant, dans certains cas où l'existence doit être vérifiée, une jointure offre de meilleures performances. Sinon, la requête imbriquée doit être traitée pour chaque résultat de la requête externe afin de garantir l'élimination des doublons. Dans de tels cas, une approche de jointure donnerait de meilleurs résultats.
donc si vous avez besoin de quelque chose comme
select * from t1 where exists select * from t2 where t2.parent=t1.id
essayez plutôt d'utiliser join. Dans d'autres cas, cela ne fait aucune différence.
Je dis: La création de functions pour les sous-requêtes élimine le problème de fouillis et vous permet d'implémenter une logique supplémentaire pour les sous-requêtes. Je recommande donc de créer des fonctions pour les sous-requêtes chaque fois que cela est possible.
L'encombrement dans le code est un gros problème et l'industrie s'efforce de l'éviter depuis des décennies.
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 pouvant découler de cas (d'utilisation) spécifiques.
(bien que Marcelo Cantos le mentionne)
Je citerai l'exemple tiré des cours Lagunita de Stanford sur SQL.
+------+--------+------+--------+
| sID | sName | GPA | sizeHS |
+------+--------+------+--------+
| 123 | Amy | 3.9 | 1000 |
| 234 | Bob | 3.6 | 1500 |
| 345 | Craig | 3.5 | 500 |
| 456 | Doris | 3.9 | 1000 |
| 567 | Edward | 2.9 | 2000 |
| 678 | Fay | 3.8 | 200 |
| 789 | Gary | 3.4 | 800 |
| 987 | Helen | 3.7 | 800 |
| 876 | Irene | 3.9 | 400 |
| 765 | Jay | 2.9 | 1500 |
| 654 | Amy | 3.9 | 1000 |
| 543 | Craig | 3.4 | 2000 |
+------+--------+------+--------+
(applications faites à des universités et des majors spécifiques)
+------+----------+----------------+----------+
| sID | cName | major | decision |
+------+----------+----------------+----------+
| 123 | Stanford | CS | Y |
| 123 | Stanford | EE | N |
| 123 | Berkeley | CS | Y |
| 123 | Cornell | EE | Y |
| 234 | Berkeley | biology | N |
| 345 | MIT | bioengineering | Y |
| 345 | Cornell | bioengineering | N |
| 345 | Cornell | CS | Y |
| 345 | Cornell | EE | N |
| 678 | Stanford | history | Y |
| 987 | Stanford | CS | Y |
| 987 | Berkeley | CS | Y |
| 876 | Stanford | CS | N |
| 876 | MIT | biology | Y |
| 876 | MIT | marine biology | N |
| 765 | Stanford | history | Y |
| 765 | Cornell | history | N |
| 765 | Cornell | psychology | Y |
| 543 | MIT | CS | N |
+------+----------+----------------+----------+
Essayons de trouver les scores GPA pour les étudiants qui ont appliqué à CS
major (quelle que soit l'université)
Utilisation d'une sous-requête:
select GPA from Student where sID in (select sID from Apply where major = 'CS');
+------+
| GPA |
+------+
| 3.9 |
| 3.5 |
| 3.7 |
| 3.9 |
| 3.4 |
+------+
La valeur moyenne pour cet ensemble de résultats est:
select avg(GPA) from Student where sID in (select sID from Apply where major = 'CS');
+--------------------+
| avg(GPA) |
+--------------------+
| 3.6800000000000006 |
+--------------------+
Utilisation d'une jointure:
select GPA from Student, Apply where Student.sID = Apply.sID and Apply.major = 'CS';
+------+
| GPA |
+------+
| 3.9 |
| 3.9 |
| 3.5 |
| 3.7 |
| 3.7 |
| 3.9 |
| 3.4 |
+------+
valeur moyenne pour cet ensemble de résultats:
select avg(GPA) from Student, Apply where Student.sID = Apply.sID and Apply.major = 'CS';
+-------------------+
| avg(GPA) |
+-------------------+
| 3.714285714285714 |
+-------------------+
Il est évident que la deuxième tentative produit des résultats trompeurs dans notre cas d'utilisation, car elle compte les doublons pour le calcul de la valeur moyenne ..__ Il est également évident que l'utilisation de distinct
avec l'instruction basée sur la jointure sera non élimine le problème, étant donné qu’il conservera par erreur une occurrence sur trois du score 3.9
. Le cas correct est de prendre en compte TWO (2) occurrences du score 3.9
, étant donné que nous avons réellement TWO (2) étudiants avec ce score conformes à nos critères de recherche.
Il semble que, dans certains cas, une sous-requête constitue la solution la plus sûre, en dehors de tout problème de performances.
Exécutez-vous sur une très grande base de données à partir d'un ancien CMS Mambo:
SELECT id, alias
FROM
mos_categories
WHERE
id IN (
SELECT
DISTINCT catid
FROM mos_content
);
0 secondes
SELECT
DISTINCT mos_content.catid,
mos_categories.alias
FROM
mos_content, mos_categories
WHERE
mos_content.catid = mos_categories.id;
~ 3 secondes
Un EXPLAIN montre qu’ils examinent exactement le même nombre de lignes, mais l’une prend 3 secondes et l’autre est quasi instantanée. Morale de l'histoire? Si la performance est importante (quand n'est-ce pas?), Essayez-la de plusieurs façons et voyez laquelle est la plus rapide.
Et...
SELECT
DISTINCT mos_categories.id,
mos_categories.alias
FROM
mos_content, mos_categories
WHERE
mos_content.catid = mos_categories.id;
0 secondes
Encore une fois, mêmes résultats, même nombre de lignes examinées. Je pense que DISTINCT mos_content.catid prend beaucoup plus de temps à comprendre que DISTINCT mos_categories.id.
Les sous-requêtes sont généralement utilisées pour renvoyer une seule ligne sous forme de 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 moment significatif d'une instruction SQL, y compris la liste de cibles, la clause WHERE, etc. Une simple sous-requête peut être utilisée comme condition de recherche. Par exemple, entre deux tables:
SELECT title FROM books WHERE author_id = (SELECT id FROM authors WHERE last_name = 'Bar' AND first_name = 'Foo');
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 valeur unique dans un ensemble d'autres valeurs, utilisez IN:
SELECT title FROM books WHERE author_id IN (SELECT id FROM authors WHERE last_name ~ '^[A-E]');
Ceci est évidemment différent de dire un LEFT-JOIN où vous voulez juste joindre des trucs des tables A et B même si la condition de jointure ne trouve aucun enregistrement correspondant dans la table B, etc.
Si vous vous inquiétez simplement de la rapidité, vous devrez vérifier votre base de données et rédiger une bonne requête afin de voir s’il existe une différence significative en termes de performances.
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 tables, une sous-requête est le meilleur résultat.
J'ai une table qui a 500 000 enregistrements sur que j'ai créé ci-dessous la requête et son temps de résultat est comme
SELECT *
FROM crv.workorder_details wd
inner join crv.workorder wr on wr.workorder_id = wd.workorder_id;
Résultat: 13.3 secondes
select *
from crv.workorder_details
where workorder_id in (select workorder_id from crv.workorder)
Résultat: 1,65 secondes
Les sous-requêtes ont la capacité de calculer des fonctions d'agrégation à la volée. Trouvez le prix minimal du livre et obtenez tous les livres vendus avec ce prix . 1) Utilisation des sous-requêtes:
SELECT titles, price
FROM Books, Orders
WHERE price =
(SELECT MIN(price)
FROM Orders) AND (Books.ID=Orders.ID);
2) en utilisant des JOIN
SELECT MIN(price)
FROM Orders;
-----------------
2.99
SELECT titles, price
FROM Books b
INNER JOIN Orders o
ON b.ID = o.ID
WHERE o.price = 2.99;
Version de MySQL: 5.5.28-0ubuntu0.12.04.2-log
J'avais aussi l'impression que JOIN est toujours préférable à 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 SELECT vrl.list_id,vrl.ontology_id,vrl.position,l.name AS list_name, vrlih.position AS previous_position, vrl.moved_date
FROM `vote-ranked-listory` vrl
INNER JOIN lists l ON l.list_id = vrl.list_id
INNER JOIN `vote-ranked-list-item-history` vrlih ON vrl.list_id = vrlih.list_id AND vrl.ontology_id=vrlih.ontology_id AND vrlih.type='PREVIOUS_POSITION'
INNER JOIN list_burial_state lbs ON lbs.list_id = vrl.list_id AND lbs.burial_score < 0.5
WHERE vrl.position <= 15 AND l.status='ACTIVE' AND l.is_public=1 AND vrl.ontology_id < 1000000000
AND (SELECT list_id FROM list_tag WHERE list_id=l.list_id AND tag_id=43) IS NULL
AND (SELECT list_id FROM list_tag WHERE list_id=l.list_id AND tag_id=55) IS NULL
AND (SELECT list_id FROM list_tag WHERE list_id=l.list_id AND tag_id=246403) IS NOT NULL
ORDER BY vrl.moved_date DESC LIMIT 200;
EXPLAIN montre:
+----+--------------------+----------+--------+-----------------------------------------------------+--------------+---------+-------------------------------------------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+----------+--------+-----------------------------------------------------+--------------+---------+-------------------------------------------------+------+--------------------------+
| 1 | PRIMARY | vrl | index | PRIMARY | moved_date | 8 | NULL | 200 | Using where |
| 1 | PRIMARY | l | eq_ref | PRIMARY,status,ispublic,idx_lookup,is_public_status | PRIMARY | 4 | ranker.vrl.list_id | 1 | Using where |
| 1 | PRIMARY | vrlih | eq_ref | PRIMARY | PRIMARY | 9 | ranker.vrl.list_id,ranker.vrl.ontology_id,const | 1 | Using where |
| 1 | PRIMARY | lbs | eq_ref | PRIMARY,idx_list_burial_state,burial_score | PRIMARY | 4 | ranker.vrl.list_id | 1 | Using where |
| 4 | DEPENDENT SUBQUERY | list_tag | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.l.list_id,const | 1 | Using where; Using index |
| 3 | DEPENDENT SUBQUERY | list_tag | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.l.list_id,const | 1 | Using where; Using index |
| 2 | DEPENDENT SUBQUERY | list_tag | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.l.list_id,const | 1 | Using where; Using index |
+----+--------------------+----------+--------+-----------------------------------------------------+--------------+---------+-------------------------------------------------+------+--------------------------+
La même requête avec JOIN est:
EXPLAIN SELECT vrl.list_id,vrl.ontology_id,vrl.position,l.name AS list_name, vrlih.position AS previous_position, vrl.moved_date
FROM `vote-ranked-listory` vrl
INNER JOIN lists l ON l.list_id = vrl.list_id
INNER JOIN `vote-ranked-list-item-history` vrlih ON vrl.list_id = vrlih.list_id AND vrl.ontology_id=vrlih.ontology_id AND vrlih.type='PREVIOUS_POSITION'
INNER JOIN list_burial_state lbs ON lbs.list_id = vrl.list_id AND lbs.burial_score < 0.5
LEFT JOIN list_tag lt1 ON lt1.list_id = vrl.list_id AND lt1.tag_id = 43
LEFT JOIN list_tag lt2 ON lt2.list_id = vrl.list_id AND lt2.tag_id = 55
INNER JOIN list_tag lt3 ON lt3.list_id = vrl.list_id AND lt3.tag_id = 246403
WHERE vrl.position <= 15 AND l.status='ACTIVE' AND l.is_public=1 AND vrl.ontology_id < 1000000000
AND lt1.list_id IS NULL AND lt2.tag_id IS NULL
ORDER BY vrl.moved_date DESC LIMIT 200;
et le résultat est:
+----+-------------+-------+--------+-----------------------------------------------------+--------------+---------+---------------------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------------------------------------------+--------------+---------+---------------------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | lt3 | ref | list_tag_key,list_id,tag_id | tag_id | 5 | const | 2386 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | l | eq_ref | PRIMARY,status,ispublic,idx_lookup,is_public_status | PRIMARY | 4 | ranker.lt3.list_id | 1 | Using where |
| 1 | SIMPLE | vrlih | ref | PRIMARY | PRIMARY | 4 | ranker.lt3.list_id | 103 | Using where |
| 1 | SIMPLE | vrl | ref | PRIMARY | PRIMARY | 8 | ranker.lt3.list_id,ranker.vrlih.ontology_id | 65 | Using where |
| 1 | SIMPLE | lt1 | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.lt3.list_id,const | 1 | Using where; Using index; Not exists |
| 1 | SIMPLE | lbs | eq_ref | PRIMARY,idx_list_burial_state,burial_score | PRIMARY | 4 | ranker.vrl.list_id | 1 | Using where |
| 1 | SIMPLE | lt2 | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.lt3.list_id,const | 1 | Using where; Using index |
+----+-------------+-------+--------+-----------------------------------------------------+--------------+---------+---------------------------------------------+------+----------------------------------------------+
Une comparaison de la colonne rows
indique la différence et la requête avec JOIN utilise Using temporary; Using filesort
.
Bien sûr, lorsque je lance les deux requêtes, la première se fait en 0,02 seconde, la seconde ne se termine pas même après une minute, donc EXPLAIN a correctement expliqué ces requêtes.
Si je n'ai pas INNER JOIN sur la table list_tag
c'est-à-dire si je supprime
AND (SELECT list_id FROM list_tag WHERE list_id=l.list_id AND tag_id=246403) IS NOT NULL
à partir de la première requête et en conséquence:
INNER JOIN list_tag lt3 ON lt3.list_id = vrl.list_id AND lt3.tag_id = 246403
à 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 à la même vitesse.
Certaines personnes disent "certains SGBDR peuvent réécrire un sous-requête en un {join) ou un joindre en un sous-requête quand il pense qu'on est plus rapide que l'autre. ", mais cette instruction s'applique aux cas simples, sûrement pas aux requêtes compliquées avec sous-requêtes qui posent effectivement des problèmes de performances.
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 une table 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 la table d'appartenance. Une fois que nous avons changé pour utiliser une sous-requête, cela a bien fonctionné.
Mais dans l'intervalle, les requêtes de jointure fonctionnent avec d'autres tables comportant moins d'entrées que la table principale.
Je pense donc que les instructions de jointure et de sous-requête fonctionnent bien et que cela dépend des données et de la situation.
De nos jours, beaucoup de dbs peuvent optimiser les sous-requêtes et les jointures. Ainsi, il vous suffit d’examiner votre requête à l’aide d’expliquer et de voir laquelle est la plus rapide. Si les performances ne sont pas très différentes, je préfère utiliser les sous-requêtes car elles sont simples et faciles à comprendre.
Je viens de penser au même problème, mais j'utilise une sous-requête dans la partie FROM . J'ai besoin de connecter et d'interroger de grandes tables, la table "esclave" a 28 millions d'enregistrements mais le résultat est seulement 128 si gros résultats. ! J'utilise la fonction MAX () dessus.
J'utilise d'abord LEFT JOIN car je pense que c'est la bonne façon, le mysql peut être optimisé, etc. La seconde fois, juste pour les tests, je réécris pour sous-sélectionner contre JOIN.
Runtime LEFT JOIN: 1.12s Runtime SUB-SELECT: 0.06s
18 fois plus rapide la sous-sélection que la jointure! Juste dans le adv Chokito. La sous-sélection a l'air terrible mais le résultat ...