Voici un scénario qui est apparu récemment au travail.
Considérez trois tableaux, A, B, C.
A a 3 000 lignes; B a 300 000 000 lignes; et C a 2 000 lignes.
Les clés étrangères sont définies: B (a_id), B (c_id).
Supposons que vous ayez une requête qui ressemble à ceci:
select a.id, c.id
from a
join b on b.a_id = a.id
join c on c.id = b.c_id
D'après mon expérience, MySQL peut choisir d'aller C -> B -> A dans ce cas. C est plus petit que A et B est énorme, et ce sont tous des équivalents.
Le problème est que MySQL ne prend pas nécessairement en compte la taille de l'intersection entre (C.id et B.c_id) vs (A.id et B.a_id). Si la jointure entre B et C renvoie autant de lignes que B, alors c'est un très mauvais choix; si commencer par A aurait filtré B jusqu'à autant de lignes que A, alors cela aurait été un bien meilleur choix. straight_join
pourrait être utilisé pour forcer cet ordre comme ceci:
select a.id, c.id
from a
straight_join b on b.a_id = a.id
join c on c.id = b.c_id
Maintenant a
doit être rejoint avant b
.
En règle générale, vous souhaitez effectuer vos jointures dans un ordre qui minimise le nombre de lignes dans l'ensemble résultant. Donc, commencer par une petite table et joindre de telle sorte que la jointure résultante soit également petite est idéal. Les choses prennent la forme d'une poire si commencer par une petite table et la joindre à une plus grande table finit par être aussi grande que la grande table.
Cela dépend cependant des statistiques. Si la distribution des données change, le calcul peut changer. Cela dépend également des détails d'implémentation du mécanisme de jointure.
Les pires cas que j'ai vus pour MySQL où tous straight_join
les indices d'index obligatoires ou agressifs sont des requêtes qui paginent sur un grand nombre de données dans un ordre de tri strict avec un filtrage de la lumière. MySQL préfère fortement utiliser des index pour tous les filtres et jointures sur les tris; cela a du sens car la plupart des gens n'essaient pas de trier toute la base de données mais ont plutôt un sous-ensemble limité de lignes qui répondent à la requête, et le tri d'un sous-ensemble limité est beaucoup plus rapide que de filtrer la table entière, qu'elle soit triée ou ne pas. Dans ce cas, mettre une jointure directe immédiatement après la table qui avait la colonne indexée que je voulais trier sur des choses fixes.
straight_join
.