MySQL : optimiser une requête en forçant l'ordre des jointures
Par Clochix le vendredi 21 novembre 2008, 13:08 - Technoweb - Lien permanent
STRAIGHT_JOIN est une extension de MySQL permettant de forcer
l'ordre dans lequel les tables d'une requête sont jointes.
Exemple pratique: soit la requête toute simple :
select s.name, count(distinct u.idUser) from s, u, p
where s.idSite = u.idSite
and u.idUser = p.idUser
group by s.i18n
order by s.i18n
censée ramener 88 lignes de résultat. Elle plantait systématiquement avec un
message d'erreur "(Errcode: 28)", ce qui signifie que MySQL
manquait de place sur le disque pour créer des fichiers temporaires. Pour
essayer de comprendre d'où venait le problème, j'ai lancé un
explain, et me suis aperçu qu'il variait selon le nombre de lignes
de résultat que je demandais (avec LIMIT). Si je limitais les
résultats à 87, l'optimisateur MySQL passait par des index:
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE s ALL PRIMARY NULL NULL NULL 88 Using filesort 1 SIMPLE u ref PRIMARY,idSite idSite 5 s.idSite 358 Using where 1 SIMPLE p ref idUser idUser 4 u.idUser 12 Using index
Par contre, si je demandais toutes les lignes, il se mettait soudain à utiliser en premier la table p, forte de 176419 enregistrements, et à passer par des fichiers temporaires pour grouper et trier:
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE p index idUser idUser 8 NULL 176419 Using index; Using temporary; Using filesort 1 SIMPLE u eq_ref PRIMARY,idSite PRIMARY 4 p.idUser 1 1 SIMPLE s eq_ref PRIMARY PRIMARY 4 u.idSite 1
La solution a été de l'obliger à effectuer la jointure d'abord sur
s et u. J'ai découvert à cette occasion l'instruction
STRAIGHT_JOIN qui, je cite la documentation,
force l'optimiseur à joindre les tables dans l'ordre dans lequel elles sont
listées dans la clause FROM. Vous pouvez utiliser cela pour accélérer la
requête, si les tables sont réordonnées sub-optimalement par l'optimiseur.
.
Ma requête, devenue select STRAIGHT_JOIN s.name ... a enfin
fonctionné. Etrange et bizarre, mais une preuve de plus de l'utilité de
EXPLAIN. Cela
dit, si un distingué membre de l'assistance a des précisions, elles seront les
bienvenues.
Commentaires
Avec MySql, en général, on ne se pose pas trop de questions, tout roule, jusqu'au jour où, je cite le bouquin "High Performance MySql": le dragon se réveille.
J'avais une appli qui tournait plutot bien, on l'a dupliquée sur un autre serveur, et là, patatras, d'une requete qui faisait initialement moins d'une demi-seconde, je suis passé à une requête atteignant presque une minute ! La seule différence que j'avais identifié, etait que MySql n'était pas tout à fait la meme version (mais très proche néanmoins).
Et c'est là que j'ai découvert la magie de EXPLAIN, qui mettait en évidence que l'optimiseur MySql n'optimisait rien du tout sur cette version ! Et ma bouée de sauvetage a été l'utilisation conjointe de STRAIGHT_JOIN et FORCE INDEX. Je suis repassé de 60 s à 0.5 s ! ouf :P