illustration de Bonnes pratiques MySQL
Mise à jour : 7 mai 2020

Quelques bonnes pratiques permettent de maintenir de bonnes performances dans une application web. La constitution d’un modèle de données réfléchi et l’indexation dans les tables reste les meilleures solutions afin de ne pas avoir de mauvaises surprises lors des développements et des audits en production.

Les plus gros problèmes de performances au niveau des bases de données sont le plus souvent le résultat d’un mauvais modèle de données et d’index manquants. Les requêtes de type SELECT sont considérés comme les requêtes les plus utilisées dans les applications web mais sont aussi surtout les requêtes prenant le plus de temps à s’exécuter.

Afin de limiter les impacts de ces requêtes, quelques points (non exhaustifs) peuvent être suivis dans le but d’atteindre des performances optimales.

Indexation

Chaque table doit avoir une clé primaire, elles permettent de trier par défaut et de joindre rapidement des tables en elles. Il est indispensable de bien s’assurer que les clés étrangères permettant de joindre les tables entre elles sont bien définies en tant qu’index.

Limiter la taille des tables

Limiter au maximum le nombre de colonnes dans les tables (elles peuvent augmenter le temps d’exécution lorsqu’on ne cherche à afficher que quelques informations) et s’assurer de mettre les valeurs pouvant être null à la fin de la table afin de ne pas prendre de place inutilement sur le disque dur.

Il est conseillé de splitter les colonnes optionnelles dans des tables séparées pouvant être récupérées à l’aide de jointures.

Analyser les requêtes

L’analyse des requêtes générée sur le serveur est de loin la meilleure solution permettant de connaître précisément le temps qu’une requête met pour être exécutée. Avec MySQL, « Slow Query Log » permet de mettre en avant les requêtes lentes sur le serveur.

Afin d’utiliser cet outil, il suffi d’activer l’option slow_query_log dans le fichier de configuration de MySQL et les requêtes lentes seront enregistrées dans un dossier spécifique. Le temps d’exécution maximum accepté avant de logger une requête peut être défini dans la configuration (il est recommandé de le mettre dans un premier temps sur 5sec puis 1sec une fois les requêtes les plus lentes améliorées).

Dans les fichiers enregistrés par « Slow Query Log », de nombreuses informations sont données comme par exemple :

  • Le temps d’exécution
  • L’utilisateur ayant exécuté la requête
  • Le nombre de lignes retournées
  • Le nombre de lignes examinées
  • Le temps verrouillé
  • La requête en elle même
Slow_query_log

Utilisation de Explain

La clause EXPLAIN ajoutée aux requêtes de type SELECT permet d’auditer les performances des requêtes. Le but est de comprendre le déroulement et les les décisions prises par MySQL lors de l’exécution de la requête.

mysql> EXPLAIN EXTENDED
    -> SELECT t1.a, t1.a IN (SELECT t2.a FROM t2) FROM t1\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: t1
         type: index
possible_keys: NULL
          key: PRIMARY
      key_len: 4
          ref: NULL
         rows: 4
        Extra: Using index
*************************** 2. row ***************************
           id: 2
  select_type: DEPENDENT SUBQUERY
        table: t2
         type: index_subquery
possible_keys: a
          key: a
      key_len: 5
          ref: func
         rows: 2
        Extra: Using index
2 rows in set, 1 warning (0.00 sec)

Comme représenté sur la figure ci dessus, le résultat obtenu lors d’une requête EXPLAIN permet de visualiser le comportement de MySQL pour retourner les données. Ces données sont sous la forme de mots clés et de chiffres.

  • id : Numéro de la requête
  • select_type : Permet connaître le type (Simple, Subquery, etc.)
  • table : Table utilisée
  • type : Type de jointure
  • possible_keys : L’index que MySQL peut choisir
  • key : L’index que MySQL a choisi
  • key_len : Taille de l’index choisi
  • ref : Indique quelle colonne est utilisée pour sélectionner
  • rows : Estimation du nombre de lignes a parcourir pour obtenir le résultat
mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Note
   Code: 1003
Message: select `test`.`t1`.`a` AS `a`,
         (`test`.`t1`.`a`,
         (((`test`.`t1`.`a`)
         in t2 on a checking NULL having
         (`test`.`t2`.`a`)))) AS `t1.a
         IN (SELECT t2.a FROM t2)` from `test`.`t1`
1 row in set (0.00 sec)

Ressources: