Tutorial PHP : chronométrer le temps de calcul des requêtes SQL (benchmark)
Par Damien Ravé - Le Caphar, lundi 26 mars 2007 à 00:06 :: Développement PHP :: #67 :: rss
Il y a quelques temps, sur notre intranet, j'ai eu affaire à d'importants ralentissements sur l'ensemble des pages. J'étais à peu près sûr qu'il s'agissait d'une requête SQL mal optimisée ou de son traitement dans une boucle PHP trop lourde. Cependant, le site étant un bric-à-brac maison constitué de nombreux modules indépendants (actus, annuaire, gestion de tickets, tableaux de bord statistiques), le problème pouvait provenir de n'importe lequel des 25 fichiers d'include chargés dynamiquement. J'avais donc besoin d'évaluer le temps consacré par le serveur à chacune des requêtes pour identifier la ou les fautives.
Il y a des outils PHP dédiés au benchmarking. Mais je n'avais (comme souvent) pas le courage de me lancer dans le déploiement d'une usine à gaz comme Pear pour une simple classe qui fait des soustractions, à en lire la documentation et à comprendre sa logique différente de la mienne. J'ai donc cherché une solution vite-fait mal-fait permettant de cerner les coupables de manière progressive, sans prise de tête.
Recette du benchmark maison au coulis de microtime
Le principe est simple : placer des marqueurs qui donnent l'heure tout au long du script en mesurant le nombre de microsecondes écoulées depuis le précédent. C'est bête et basique, et je pourrais en rester là. Mais je vais vous donner les ingrédients qui tiennent en deux fonctions très simples et quelques print bien placés.
Ingrédients
-
une fonction qui donne l'heure (à placer dans vos includes)
function getmicrotime() { // découpe le tableau de microsecondes selon les espaces list($usec, $sec) = explode(" ",microtime()); // replace dans l'ordre return ((float)$usec + (float)$sec); } -
une fonction qui affiche le temps écoulé
/** *@desc Affiche le temps écoulé (en microsecondes) depuis la dernière étape. * L'argument $nom_etape permet de spécifier ce qui est mesuré (ex. "page de stats" ou "requête numéro 7") */ function benchmark ($nom_etape) { global $etape_prec; $temps_ecoule = ($etape_prec) ? round((getmicrotime() - $etape_prec)*1000) : 0; $retour = '<p class="alerte">' . $nom_etape . ' : ' . $temps_ecoule . 'ms</p>'; $etape_prec = getmicrotime(); return $retour; } -
des marqueurs répartis après les principales requêtes
Lorsque vous placez un marqueur avec print benchmark('pointeur');, le script va calculer le temps écoulé depuis le dernier appel et l'afficher dans la page Web. Deux marqueurs peuvent suffire pour benchmarker une page : un au début et un à la fin. Mais l'idéal c'est d'en rajouter à différentes étapes de la page pour "resserrer" la recherche autour d'une partie spécifique.
include("modules/mod_actus.php"); print benchmark("Module actus"); // renvoie Module actus : 26 ms include("modules/mod_contacts.php"); print benchmark("Module contacts"); // renvoie Module contacts : 47 ms include("modules/mod_stats.php"); print benchmark("Module stats"); // renvoie Module stats : 1289 msDans l'exemple ci-dessus, on identifie rapidement que le module stats effectue un traitement anormalement long, ce qui permet de se concentrer sur le script en question (mod_stats.php). A l'intérieur de ce script, on pourra placer de nouveaux marqueurs pour "resserrer" le filet autour de la requête fautive :
mysql_query($requete1); print benchmark("Requête 1"); // renvoie Requête 1 : 82 ms mysql_query($requete2); print benchmark("Requête 2"); // renvoie Requête 2 : 1013 ms mysql_query($requete3); print benchmark("Requête 3"); // renvoie Requête 3 : 94 msVoilà ! Nous avons cerné le coupable, qui met plus d'une seconde à s'effectuer. Il ne reste plus qu'à optimiser la requête pour alléger le script, ou à se passer de cette fonctionnalité si elle est décidément trop gourmande.
Conseils de cuisson
-
Attention ! Le temps de calcul rapporté est uniquement celui nécessaire à la génération du script par le serveur. Il n'inclut pas le temps d'envoi de la requête par le client, celui de l'envoi des données générées par le serveur ou encore le temps de mise en forme de la page par le navigateur du visiteur (qui peut être important s'il y a beaucoup de javascript, styles CSS complexes, etc.).
-
Attention à ne pas oublier un marqueur en route. Sinon le décompte du temps intitulé "Module 5" pourrait bien recouvrir les modules 3, 4 et 5...
-
Pour masquer le benchmark aux utilisateurs et le réserver aux admins de l'intranet, je passe ma variable $utilisateur en global dans la fonction benchmark(), et je vérifie que $utilisateur->possedeDroits('admin') avant de renvoyer $retour
-
L'usage de print peut provoquer une erreur avant l'envoi des en-têtes HTTP ("headers already sent by..."). Placez la première juste après les headers ou utilisez l'output buffering.
Ranger les ustensiles
Une fois le benchmarking effectué, vous pouvez supprimer l'ensemble des marqueurs insérés dans les scripts pour le désactiver. Mais si vous êtes un fainéant (comme moi) ou que vous pensez qu'ils vont resservir, il est plus rapide de désactiver simplement l'affichage des valeurs de retour en plaçant en commentaire la ligne // return $retour ; de la fonction benchmark. Il suffira de le réactiver à la prochaine occasion.
A vos fourneaux !
A lire sur le même thème
- 10 fonctions PHP-MySQL que j'utilise tous les jours
- Tutoriel PHP : pourquoi passer au développement orienté objet ?
- Astuce PHP : afficher ou masquer le "s" de résultat(s) en une ligne
- Tutorial MySQL : alléger des requêtes successives avec CREATE TEMPORARY TABLE
- Erreurs 404 : faites la chasse aux pages perdues
Articles les plus lus
- Tendances Web 2007 : 60 palettes de couleur élégantes pour vos sites Web
- Tout ce qu'il faut savoir sur le PageRank Google (traduit de l'anglais)
- 7 pratiques Javascript qui changent la vie
- Planète Bosphore
- Quelle est la meilleure architecture pour votre site Web ?
- 10 fonctions PHP-MySQL que j'utilise tous les jours

Commentaires
1. Le lundi 26 mars 2007 à 20:33, par Julien Tartarin- Tutorial PHP : chronométrer le temps de calcul des requêtes SQL (benchmark)
Julien Tartarin a posté 1 commentaire dans les articles suivants :
2. Le mardi 27 mars 2007 à 13:17, par Damien Ravé (le Caphar)- Comment perdre vos clients grâce à un nouveau design : la parabole de la ligne 13
- Et toi tu fais quoi dans la vie ? (entretien avec un webdesigner)
- Yahoo UI vs JQuery : quel framework Javascript pour vos applications Web 2.0 ?
- Vous voulez survivre ? Soyez un filtre.
- Comment référencer un site professionnel sur Google : oubliez les meta tags
- Quel est votre manque-à-bloguer ? (encore une chaîne de blogs !)
- Tutoriel : créez une FAQ accessible et facile à mettre à jour avec JQuery
- Tutoriel PHP : pourquoi passer au développement orienté objet ?
- Stats du blog en juin : 11000 visiteurs, 36000 pages vues, et... 11,19 dollars de recettes publicitaires
- 10 choses que les femmes attendent des hommes d'aujourd'hui
- Nouveau design enrichi : le Potlatch prend le large
- Le marketing est un humanisme
- Carla Bruni nue : que fait Sarkozy ?
- Dix ans après, le Web sert toujours à se regarder le nombril
- Antispam pour les commentaires de blog : un Captcha sans images
- 10 fonctions PHP-MySQL que j'utilise tous les jours
- Des tableaux de données simples, standards et lisibles en CSS et PHP
- Planète Djemma el'Fna
- Tendances Web 2007 : 60 palettes de couleur élégantes pour vos sites Web
- Développeurs Web : c'est le moment de demander une augmentation
- Vos utilisateurs buggent ? Quelques pièges à éviter dans vos applications en ligne
- Quelle est la meilleure architecture pour votre site Web ?
- 7 pratiques Javascript qui changent la vie
- Planète Bosphore
- Astuce PHP : afficher ou masquer le "s" de résultat(s) en une ligne
- Sarkozy ou le retour de la peine de mort dans l'oeuf
- Nouvelle affiche de campagne de Nicolas Sarkozy
- Tutorial PHP : chronométrer le temps de calcul des requêtes SQL (benchmark)
- Démago ou l'urgence médiatique
- 10 fonctions PHP-MySQL que j'utilise tous les jours
- Pour la triche à l'école (anglais)
- 10 fonctions PHP-MySQL que j'utilise tous les jours
- Je veux être une star underground - 1. l'artiste est un grand malade
- Ceux qui ne veulent pas de Sarkozy comme président
Damien Ravé (le Caphar) a posté 34 commentaires dans les articles suivants :
3. Le mercredi 28 mars 2007 à 14:23, par Julien Tartarin- Tutorial PHP : chronométrer le temps de calcul des requêtes SQL (benchmark)
Julien Tartarin a posté 1 commentaire dans les articles suivants :
Ajouter un commentaire