Guide rapide de la question MySQL bien posée

Oui!  Toi mon ami!  Oui!  Toi!  C’est à toi que je m’adresse!  Celui que je dépanne et que j’aide « gratis » à chaque jour!

Je réponds quotidiennement à des questions au sujet de MySQL, principalement de requêtes et d’optimisation.  Que ce soit sur dBForums, Stack Overflow, MySQL.com, developpez.net ou sur IRC (irc.freenode.net, channel #mysql), c’est toujours la même chose.  Si tu veux que je t’aide, aide-moi à t’aider!

Donc, un petit guide de ce qu’il faut faire pour qu’on puisse résoudre ton problème le plus rapidement possible.

Explique ton problème clairement

Si tu es incapable d’expliquer, en une phrase, ce que tu tentes de faire, ça part mal!  Encore faudrait-il que tu saches ce que tu veux et ce dont tu parles!

Par exemple : « je cherche le meilleur vendeur pour chaque magasin se trouvant dans un district qui vend moins que la moyenne nationale« . Ça, c’est clair et limpide!

Cependant, « ma requête est lente, la voici » :

SELECT 
 COUNT(*) AS x1k1, w.nndt, w.n01_d
FROM 
 p_usr_htgg w
WHERE
 EXISTS (SELECT 
    w2.id
   FROM 
    puw_user w2
   LEFT JOIN 
    temp_eoms te ON te.mt = w2.mt
   WHERE 
    w2.k1 = w.k1 AND w.sales = MAX(w2.sales)
   )
GROUP BY 
 w.nndt, w.n01_d
HAVING 
 COUNT(*) > 3
ORDER BY 
 x1k1 DESC
LIMIT 
 0, 100

Tu vois la différence? Dans un des 2 cas le problème est clair! Dans le second cas, juste à voir la requête je n’ai pas le goût de t’aider!

Et utilise des noms de tables et de colonnes que je puisse comprendre! Les acronymes et abbréviations cryptiques ne m’aident pas!  Pas plus que si tes noms de tables ou de colonnes sont en italien, en espagnol ou en allemand!

Sois précis

« J’ai une base de données gigantesque avec énormément d’usagers concurrents et ma requête est très lente et elle est effectuée très souvent« .

Ce qui est « gigantesque » pour toi est probablement ridicule pour Google, Amazon et GitHub ou quelqu’un qui oeuvre dans le domaine de la bio-informatique : donne-moi des chiffres!

« Énormément« , c’est bien souvent relatif!  50 usagers concurrents et une table de 100 millions d’enregistrements sur une machine avec 2G de RAM, c’est effectivement énorme!  Mais avec un serveur 16 processeurs et 128G de RAM, c’est minuscule : donne-moi des chiffres!

« Souvent », c’est quoi pour toi? 200 fois par minute? 15 fois par minute? Quoi? Donne-moi des chiffres!

Qu’est-ce que la lenteur pour toi? 3 secondes ou 0.2 secondes? Donne-moi des chiffres!

Ne me fais pas googler à ta place

Fais un minimum d’effort!  Il me faut souvent moins de temps pour trouver un lien qui te réfère à la solution que tu en as pris à écrire la question!  Tu te serais sauvé du temps si tu avais googlé à ma place! Et moi aussi j’en aurais sauvé!

Quelques données et les résultats attendus

« Oui mais je devrais avoir 6 records de xyz pour ce abcd et j’en ai seulement 5 ».

Cela ne me dit strictement rien!  Je ne connais pas ta base de donnée, ou ton domaine, pas plus que tes tables ou les colonnes de tes tables.  Encore moins tes données, leur type, leur répartition, leur sélectivité, etc…

Un exemple de table, de données et ta requête, ça se fait en 2 minutes sur SQLFiddle!

Fournis-moi le EXPLAIN

Ta requête est lente…  So what!  Pour quelles raisons?  Je ne le sais pas plus que toi!  Si tu ne me fournis pas le EXPLAIN, je suis incapable de t’aider, encore moins de savoir pourquoi MySQL choisit un plan d’accès aussi moche!

Montre-moi le SHOW CREATE TABLE

Même si j’ai le EXPLAIN, il me faut la SHOW CREATE TABLE, c’est aussi simple que ça!  L’un ne va pas sans l’autre!

Est-ce que dans ta jointure les 2 clés sont du même type et de la même longueur?  Est-ce que le LIKE est lent parce qu’on scanne une colonne de texte de 4Mb ou que t’as un BLOB de 1G qui contient un vidéo dans chaque enregistrement?  Est-ce que ta table est de type InnoDb, MyISAM ou autre?

Apprend à utiliser SHOW VARIABLES

Dans certains cas, ton problème n’est pas ta requête SQL mais certains paramètres de ta session, ton serveur, etc.  Tu dois savoir utiliser SHOW VARIABLES!

Apprend à utiliser SHOW STATUS

Tu dois savoir être en mesure de vérifier l’état de ton serveur.  C’est primordial ! SHOW STATUS est un autre de tes amis précieux!

Apprend à utiliser SHOW TABLE STATUS

SHOW TABLE STATUS te permettra, en un rapide coup d’oeil, d’avoir un aperçu des tables de ta base de donnée : leur type, le nombre de records, la taille moyenne des records, etc.

Donne-moi des données volumétriques

Te l’ai-je dit plus haut?  Donne-moi des chiffres!

Tes requêtes s’exécutent quasiment toutes en 0.1 seconde mais ton serveur est essoufflé?  Pourquoi? Peut-être que je devrais savoir que tu as 3500 usagers concurrents qui vargent sur le même serveur! Ou que ta requête est exécutée 900 fois par minute!

Ta requête prend 27 secondes? Je devrais peut-être savoir que cette table a 728 millions d’enregistrements!

Tu te demandes pourquoi le EXPLAIN montre un table scan même si tu as tous les indexes au monde sur cette table? Peut-être que MySQL a choisi de faire un full table scan parce que ta table de jointure a seulement 8 enregistrements!

Un minimum de contexte m’aide à comprendre ce qui se passe!

Respire : ne capote pas!

« J’ai une HYPER GROSSE base de données, avec une requête qui a 2 jointures qui roule aux 15 secondes.  J’ajoute à la table principale 2500 records par mois… »

Tu n’es pas dans Excel!  Respire!  Pour mon amusement personnel, j’ai un serveur avec plus de 10000 tables à la maison.  Tout est question de hardware et de perspective et chaque base de donnée a ses particularités.

À moins que ton intention soit de compétionner Google ou qu’une requête soit *vraiment* problématique, n’essaie pas de faire en sorte que chaque requête roule en moins de 100 millisecondes!

Ne me fais pas suer à t’aider pendant 4 heures sur une requête de rapport annuel qui prend 5 minutes un 1er janvier à 2h15 de la nuit et qui roule une fois par année! Choisis tes combats!  J’veux bien t’aider mais pas perdre mon temps!

Arrête de vouloir tout optimiser aveuglément!

Utilise SQLFiddle

C’est facile, utile et pratique.  Et c’est gratuit! Et c’est ici. Et ça nous permet de travailler sur exactement la même chose!

Utilise un pastebin

S’il te plait, n’inonde pas le channel IRC avec une requête de 35 lignes! Utilise SQLFiddle ou un pastebin. Y’a Pastie, gist.github et pastebin.com.

Utilise le client MySQL

Certains problèmes sont extrêmement subtils et difficiles à comprendre et à isoler.  La dernière chose dont j’ai besoin, c’est du code PHP, une application client merdique comme PHPMyAdmin ou un autre outil boiteux.  Le client MySQL fonctionne à merveille et c’est parfait et tout ce dont tu as besoin.  Au pire, utilise des outils solides comme HeidiSQL mais pas PHPMyAdmin s’il te plait!

Et où que tu sois, sur toutes les plates-formes, le client MySQL est là! Un seul outil à apprendre et à maîtriser!

Utilise \G

Au lieu de me forcer à scroller vers la droite pendant une éternité pour que je puisse voir les résultats d’une requête, d’un EXPLAIN ou d’un SHOW TABLE STATUS, ajoute \G à la fin!

Ça limite l’affichage à 80 caractères et les données sont disposées de façon verticale.  C’est beaucoup plus lisible quand les résultats dépassent 80 caractères par ligne!

Mais en toute circonstance, va au plus simple.  Si le résultat est affichable sans \G, ça me va!  Si j’ai à scroller vers la droite parce que je ne peux pas voir la ligne entière, utilise \G!

Formatte ton code

SELECT count(*) as
x1k1, w.nndt, 
w.n01_d
from P_USR_HTGG 
w where exists (
SELECT w2.id FROM puw_user w2
left join 
temp_eoms te ON te.mt = w2.mt where 
w2.k1 = w.k1 AND w.sales = 
MAX(w2.sales))
group by w.nndt,
w.n01_d
having count(*) > 3
order BY x1k1 
desc limit 0, 100

Tu vois clairement tout ce qui se passe dans cette requête? Pas moi! Et c’est exactement la même requête que celle présentée plus haut! Laquelle des deux trouves-tu la plus lisible?

Applique-toi à mettre les mots réservés en majuscules! Regarde comment les parties d’une requête sont regroupées et indentées. S’il faut scruter ta requête à la loupe pour identifier la clause WHERE, le EXISTS, le COUNT, le GROUP BY et les autres indices nécessaires à la compréhension de ta requête, ça ne facilite la tâche à personne!

Ne sois pas trop fébrile

Y’a déjà 30 minutes qu’on travaille ensemble sur ta requête et tu es satisfait du résultat, ton problème est enfin résolu? Il ne te manquait qu’un index?

Ne te précipite pas pour ajouter l’index manquant en production! Ce qui a pris 3 secondes sur tes données de test peut prendre des heures en production!  Par ailleurs, vérifies que tu as un backup avant de toucher à la prod!

Ça semble idiot comme conseil mais pas plus tard que la semaine passé, un type que j’ai aidé, pris d’un enthousiasme démesuré, a eu la bonne idée d’immédiatement créer l’index qui lui manquait en production… en oubliant le fait qu’il avait 94 millions d’enregistrements dans cette table!

La création de l’index a pris quelques heures… en plein aux heures de pointe du serveur!  Outch!

Sois ouvert à la critique

Dans bien des cas, le mauvais design des tables ou la façon de représenter tes données est 95% de ton problème. Sois ouvert aux suggestions : je n’essaie que de t’aider!

Comme ici.

Dis merci

J’aide les gens parce que ça me fait plaisir et que la diversité des problèmes rencontrés m’aide à rester sharp et up-to-date avec MySQL.  Si je passe 2 heures à t’aider et à te donner de mon temps, un merci c’est bien peu cher payé et très apprécié!

 

 

 

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :