TECHNOLOGIES / MySQL
MySQL : la base de données relationnelle de nos projets Symfony
MySQL est le système de gestion de base de données relationnelle open source le plus utilisé au monde. Chez SmartBooster, il equipe l'ensemble de nos projets Symfony via Doctrine ORM, conteneurisé dans notre stack Docker standard.
Cette page vous explique pourquoi nous avons fait ce choix, compare les performances entre versions et documente les commandes utiles au quotidien pour l'équipe.
PRÉSENTATION
Qu'est-ce que MySQL ?
MySQL est un SGBDR (Système de Gestion de Bases de Données Relationnelles) open source créé en 1995 par Michael Widenius. Aujourd'hui maintenu par Oracle, il est utilisé par des millions d'applications dans le monde, des blogs WordPress aux systèmes transactionnels d'entreprise.
Son moteur de stockage InnoDB, devenu le défaut depuis MySQL 5.5, garantit les propriétés ACID : Atomicité, Cohérence, Isolation et Durabilité. Chaque transaction est soit entièrement appliquée, soit entièrement annulée, même en cas de crash serveur.
Chez SmartBooster, MySQL s'intègre dans notre stack via Doctrine ORM qui génère les requêtes SQL optimisées et gère les migrations de schéma depuis le code source PHP.
POURQUOI MYSQL
Ce qui en fait notre standard de base de données
MySQL est présent sur tous nos projets Symfony dès le premier jour. Voici pourquoi nous ne développons plus sans lui.
Base de référence de l'écosystème Symfony
MySQL est la base de données par défaut des projets Symfony chez SmartBooster. Doctrine ORM génère des requêtes optimisées pour MySQL et notre template symfony-docker intègre MySQL nativement dans la stack de développement.
Transactions ACID et fiabilité InnoDB
Le moteur InnoDB garantit des transactions atomiques, une cohérence des données après crash et des clés étrangères avec contraintes d'intégrité. Aucune donnée corrompue en cas de coupure réseau au milieu d'un INSERT groupé.
Performance indexée pour les applications métier
Les index composites, les index couvrants et le query optimizer MySQL s'intègrent avec Doctrine ORM. L'essentiel des gains de performance vient de la structure des index et des requêtes, pas de la version MySQL. C'est par là que commence notre audit de performance.
Image Docker officielle prête à l'emploi
L'image officielle mysql:8.4 est disponible sur Docker Hub et intégrée dans notre stack Docker standard. Démarrage en une commande, données persistées dans un volume nommé, configuration via variables d'environnement.
Migrations de schéma versionnées avec Doctrine
Les migrations Doctrine générées depuis les entités PHP créent des scripts SQL versionnés et rejouables. Chaque evolution du schéma est tracée dans Git et déployée automatiquement en CI avant chaque mise en production.
Deux versions LTS au choix
MySQL 8.4 LTS (support jusqu'en 2032) et MySQL 9.7 LTS sorti avril 2026 (support jusqu'en 2034). Pour les projets existants sur 8.4 : aucune migration forcée avant 2032. Pour les nouveaux projets, MySQL 9.7 LTS est le choix naturel.
PERFORMANCE
MySQL par version : gains de performance
MySQL publie régulièrement de nouvelles versions LTS et Innovation. Voici les gains de performance observés sur des applications web PHP/Symfony standards, mesurés via des benchmarks sysbench OLTP sur des charges mixtes lecture/écriture.
| Saut de version | Gain typique | Explication |
|---|---|---|
| MySQL 5.6 → 5.7 | Scalabilité (forte concurrence) | Refonte de la scalabilité InnoDB en read-write : purge multi-threadée, pool de buffer mieux partitionné et statistiques adaptatives de l'optimiseur. Percona observe un net gain de débit à forte concurrence (plusieurs centaines de connexions simultanées). À faible concurrence en revanche, 5.7 n'apporte pas de gain et peut rester légèrement derrière 5.6, son exécution mono-thread étant plus lente. |
| MySQL 5.7 → 8.0 | 5.7 souvent plus rapide | Contrairement à l'idée reçue, MySQL 8.0 n'est pas toujours plus rapide que 5.7. Sur un test sysbench à 24 threads, Percona mesure 5.7 plus rapide dans toutes les configurations : de 12 à 22 % avec les binary logs activés (cas standard pour la réplication), de 5 à 16 % sans. L'intérêt de migrer vers 8.0 est avant tout fonctionnel : CTE, Window Functions, roles, JSON enrichi et Atomic DDL. |
| MySQL 8.0 → 8.4 LTS | Marginal (< 5 %) | La version 8.4 LTS est une consolidation, pas une refonte de moteur. Les gains de performance sont anecdotiques sur les workloads applicatifs classiques. L'intérêt de la migration est exclusivement la sécurité et la garantie de support jusqu'en 2032, pas le débit. |
| MySQL 8.4 → 9.7 LTS | +6.5 % (moyenne PGO) +14.3 % (pic) 32 Go, 1 thread | MySQL 9.7 LTS est le premier binaire MySQL compilé avec le PGO (Profile-Guided Optimization) : le compilateur analyse les chemins d'exécution chauds lors d'un profiling réel, puis recompile l'ensemble du code en ciblant ces chemins. Percona mesure +6.5 % en moyenne sur sysbench OLTP, avec un pic à +14.3 % sur les configurations 32 Go (grand buffer pool) à faible concurrence. Le gain est le plus fort avec un grand buffer pool et s'amenuise sur les petites configurations mémoire et à très haute concurrence. |
Les gains indiqués sont des ordres de grandeur issus de benchmarks sysbench OLTP et de mesures en conditions réelles sur des applications PHP/Symfony. Ils varient selon le ratio lecture/écriture, la taille des tables, la configuration du pool de buffer InnoDB et l'infrastructure. Ces chiffres ne se substituent pas à un profiling sur votre propre application. Sources : Percona : MySQL 5.7 read-write benchmarks, Percona : MySQL 8 n'est pas toujours plus rapide que 5.7, Percona : MySQL 9.7.0 PGO benchmark analysis, Percona : rapport 2026 MySQL ecosystem benchmark.
HISTORIQUE
Versions de MySQL
MySQL suit un double calendrier depuis 2024 : le canal LTS (Long Term Support, tous les 2-3 ans) pour la stabilité en production, et le canal Innovation (trimestriel) pour les nouvelles fonctionnalités. Voir les dates de fin de support officielles →
Chez SmartBooster, nous utilisons exclusivement des versions LTS en production. Les versions du canal Innovation (sorties trimestrielles : 8.1 à 8.3, 9.0 à 9.6) apportent les nouvelles fonctionnalités mais sans garantie de support long terme : leur description ci-dessous précise qu'elles ne sont pas des LTS et qu'elles sont rapidement éclipsées par la LTS suivante.
-
MySQL 26.7
Support actifJuil. 2026
aucune fin de support annoncée
Première publication du versionnement calendaire : AA.M, soit juillet 2026. Canal Innovation, destiné aux équipes qui suivent les nouveautés au rythme trimestriel. Pour un logiciel métier, la LTS reste la cible.
- Versionnement calendaire
La 9.7 est la dernière version numérotée séquentiellement. Les suivantes prennent la forme AA.M : 26.7 pour juillet 2026, 27.7 pour juillet 2027. Une version LTS garde son numéro pendant toute sa durée de support. - Canal Innovation
Publication destinée aux équipes qui veulent les dernières fonctionnalités et disposent de tests automatisés. Pour un projet métier en production, la LTS reste la cible.
- Versionnement calendaire
-
MySQL 9.7 LTS
RecommandéeAvr. 2026
support actif jusqu'en avr. 2031
Deuxième version LTS d'Oracle depuis le passage au cycle LTS / Innovation, et la dernière à porter un numéro séquentiel. Elle consolide ce qui a été éprouvé dans les publications 9.0 à 9.6. Le choix naturel pour tout nouveau projet.
- LTS : 5 ans de support Premier, 3 ans de plus en Extended
Une série LTS suit la politique de support Oracle et ne reçoit que les correctifs nécessaires : aucune fonctionnalité n'est retirée en cours de série. C'est la cible pour un projet en production qui ne veut pas subir de changement de comportement. - Le canal Innovation consolidé
La LTS reprend ce qui a été éprouvé dans les publications 9.0 à 9.6, dont le type VECTOR introduit en 9.0. Elle évite de suivre un rythme de publication trimestriel.
- LTS : 5 ans de support Premier, 3 ans de plus en Extended
-
MySQL 9.0 → 9.6
Obsolète depuis avr. 2026Juin 2024
plus de correctifs depuis avr. 2026
Versions du canal Innovation d'Oracle : sorties trimestrielles avec de nouvelles fonctionnalités sans garantie de support long terme. Cette branche non-LTS n'est plus maintenue depuis la sortie de 9.7 LTS, qui a intégré ses fonctionnalités stables.
- Type VECTOR
Type de colonne pour stocker des vecteurs. Utilisé pour les recherches de similarité (RAG, recommandations) sans extension tierce. - Programmes stockés en JavaScript, en Enterprise Edition
CREATE FUNCTION ... LANGUAGE JAVASCRIPT permet d'écrire de la logique directement dans la base. Réservé à MySQL Enterprise Edition : indisponible sur la version Community, celle qu'utilisent la quasi-totalité des hébergements.
- Type VECTOR
-
MySQL 8.4 LTS
Support actif avr. 2029Avr. 2024
support actif jusqu'en avr. 2029
Première version LTS officielle d'Oracle pour MySQL 8.x, toujours en support actif. Recommandée pour les projets existants : elle ne force aucune migration à court terme.
- Première LTS du modèle Oracle
Correctifs de sécurité jusqu'en avril 2032. La cible pour un projet en production qui veut éviter les migrations fréquentes. - mysql_native_password désactivé par défaut
L'ancien mécanisme d'authentification est désactivé : les comptes applicatifs créés avant 8.0 ne peuvent plus se connecter tant que le plugin n'est pas réactivé ou le compte migré. C'est le premier blocage rencontré lors d'une montée depuis 8.0. - Valeurs par défaut InnoDB revues
Plusieurs variables système InnoDB changent de valeur par défaut, et des options dépréciées depuis 8.0 sont supprimées. Un audit de la configuration serveur est nécessaire avant la bascule.
- Première LTS du modèle Oracle
-
MySQL 8.1 → 8.3
Obsolète depuis avr. 2024Juin 2023
plus de correctifs depuis avr. 2024
Premières versions du nouveau canal Innovation d'Oracle, introduit avec la bifurcation de la branche MySQL 8.x. Ces versions trimestrielles non-LTS ont été éclipsées par la sortie de MySQL 8.4 LTS en avril 2024.
-
MySQL 8.0
Obsolète depuis avr. 2026Avr. 2018
plus de correctifs depuis avr. 2026
Version majeure avec refonte de la gestion des droits, JSON enrichi et Window Functions. Avant le modèle LTS / Innovation, MySQL 8.0 a assuré un cycle de support inhabituellement long. La migration vers 8.4 LTS ou 9.7 LTS est aujourd'hui urgente.
- Roles et gestion des droits
Les roles MySQL permettent de regrouper des ensembles de privilèges et de les assigner à plusieurs utilisateurs. Remplace les scripts de GRANT laborieux. - Window Functions
ROW_NUMBER(), RANK(), LAG(), LEAD()... Les fonctions analytiques permettent des agrégations glissantes et des classements sans sous-requêtes imbriquées complexes. - CTE (Common Table Expressions)
Les expressions WITH améliorent la lisibilité des requêtes complexes. Les CTE récursives permettent de parcourir des structures arborescentes (catégories imbriquées, commentaires) en SQL natif. - Atomic DDL
Les opérations DDL (CREATE, DROP, ALTER) sont atomiques et enregistrées dans le redo log. Plus de tables orphelines ou d'état incohérent après un crash pendant un ALTER TABLE en production. - UTF8MB4 par défaut
L'encodage 4 octets devient le défaut, couvrant l'intégralité d'Unicode dont les emojis. Fin des truncations silencieuses sur les champs VARCHAR avec des caractères hors BMP.
- Roles et gestion des droits
-
MySQL 6 et 7
Versions inexistantesNon publiés
pas encore publiée
MySQL 6.0 a été lancé en développement en 2007 puis abandonné après le rachat de MySQL AB par Sun Microsystems en 2008. Les fonctionnalités utiles ont été réintégrées dans la branche 5.x. MySQL 7.x est réservé à MySQL Cluster NDB, la variante distribuée de MySQL. Oracle a sauté directement à MySQL 8.0 en 2018 pour éviter toute ambiguïté de numérotation.
-
MySQL 5.7
Obsolète depuis oct. 2023Oct. 2015
plus de correctifs depuis oct. 2023
Version qui a introduit le type JSON natif et amélioré InnoDB de façon significative. Tout projet encore sur MySQL 5.7 doit migrer immédiatement.
- Type JSON natif
Stockage optimisé et indexation de documents JSON directement dans InnoDB. Opérateurs ->, ->> et JSON_EXTRACT() pour accéder aux champs sans désérialiser. - Generated columns
Colonnes virtuelles calculées depuis d'autres colonnes, indexables sans stockage physique (VIRTUAL) ou matérialisées (STORED). Utiles pour indexer un champ extrait d'un document JSON. - sys schema
Base de données de diagnostic pré-installée avec des vues lisibles des tables performance_schema. Simplifie considérablement l'identification des requêtes lentes et des locks.
- Type JSON natif
-
MySQL 5.6
ObsolèteFévr. 2013
plus de correctifs depuis févr. 2021
La version qui a modernisé InnoDB et introduit la réplication GTID. Elle ne doit plus être utilisée en production.
- Réplication GTID
Les Global Transaction Identifiers simplifient la gestion des architectures de réplication en identifiant chaque transaction de façon unique sur tous les noeuds. - Online DDL
Les ALTER TABLE s'exécutent sans verrouiller complètement la table en lecture. Les migrations de schéma sur des tables volumineuses deviennent moins risquées en production. - Full-text search InnoDB
La recherche full-text étendue nativement à InnoDB (auparavant réservée à MyISAM). Utilisable pour la recherche textuelle sans solution tierce pour les volumes modérés.
- Réplication GTID
-
MySQL 5.5
ObsolèteDéc. 2010
plus de correctifs depuis déc. 2018
La version qui a fait d'InnoDB le moteur par défaut, remplaçant définitivement MyISAM pour les tables transactionnelles. Introduction de la semi-synchronous replication et du Performance Schema.
- InnoDB moteur par défaut
InnoDB remplace MyISAM comme moteur de stockage par défaut. Transactions ACID, clés étrangères et récupération sur crash deviennent le standard MySQL. - Performance Schema
Nouvelle base de données de monitoring avec des tables d'instrumentation du serveur. Ancêtre du sys schema de MySQL 5.7, orienté DBA plutôt que développeur.
- InnoDB moteur par défaut
-
MySQL 5.0
ObsolèteOct. 2005
plus de correctifs depuis janv. 2012
Version majeure qui a apporté les fonctionnalités attendues d'un SGBDR professionnel : procédures stockées, vues et déclencheurs.
- Procédures stockées
Logique métier encapsulée côté base de données, exécutable via CALL. Réduit les allers-retours réseau sur les traitements complexes. - Vues (Views)
Tables virtuelles basées sur des requêtes SELECT, permettant de simplifier l'accès aux données et de gérer les droits par vue. - Triggers
Déclencheurs exécutés automatiquement sur INSERT, UPDATE ou DELETE. Utilisés pour l'audit, la dénormalisation automatique ou les contraintes complexes.
- Procédures stockées
-
MySQL 4.0 / 4.1
Obsolète2003-2004
plus de correctifs depuis déc. 2009
Introduction des sous-requêtes (4.1), de la commande UNION et de l'intégration optionnelle d'InnoDB. Première étape vers un SGBDR complet.
-
MySQL 3.23
Obsolète2001
plus de correctifs depuis déc. 2006
Première version avec le support optionnel d'InnoDB et de MyISAM. Introduction de la réplication master-slave. Début de la popularisation sur les hébergements mutualisés.
Rester sur une version active de MySQL, c'est bénéficier des correctifs de sécurité et de la compatibilité avec les dernières versions de PHP et Doctrine ORM. Une version obsolète expose votre application à des vulnérabilités non corrigées et bloque les mises à jour de vos dépendances Symfony.
NOTRE USAGE
Comment nous utilisons MySQL chez SmartBooster
MySQL est au coeur de tous nos projets Symfony. Voici les trois piliers qui structurent notre usage au quotidien.
Entités et Repositories Doctrine
Chaque table MySQL correspond à une entité PHP annotée avec les attributs Doctrine. Le Repository associé centralise toutes les requêtes sur cette table. Cette séparation garantit que la logique de persistance ne se dilue pas dans les controllers ou les services.
Migrations versionnées (up/down)
Chaque modification de schéma génère un fichier de migration avec une méthode up() (applique le changement) et down() (annule le changement). Ces fichiers sont versionnés dans Git et déployés automatiquement en CI : la structure de la base reste toujours synchronisée avec le code, sans intervention manuelle.
Fixtures de développement
Des fixtures standardisées alimentent chaque environnement de développement avec des données cohérentes et reproductibles. Chaque développeur qui clone le projet rejoue les fixtures et retrouve immédiatement un état de base connu, sans dépendre d'un dump personnel.
MOTEURS DE STOCKAGE
InnoDB, MyISAM et les autres moteurs MySQL
MySQL supporte plusieurs moteurs de stockage interchangeables par table. En pratique, InnoDB est le seul choix pertinent pour les applications Symfony en production depuis MySQL 5.5 (2010).
| Moteur | Transactions ACID | Clés étrangères | Usage |
|---|---|---|---|
| InnoDB | Oui | Oui | Moteur par défaut depuis MySQL 5.5. Le seul choix pour toute table applicative avec Symfony/Doctrine : transactions, contraintes d'intégrité et récupération après crash. |
| MyISAM | Non | Non | Moteur historique, plus rapide en lecture pure sur les très vieilles versions MySQL, mais sans sécurité transactionnelle. A éviter sur tout nouveau projet. |
| MEMORY | Non | Non | Données stockées en RAM, volatiles au redémarrage. Utile pour des tables temporaires dans des procédures stockées ou des caches intermédiaires. |
| ARCHIVE | Non | Non | Stockage compressé en append-only, sans mise à jour ni suppression possible. Pour des journaux d'audit à très fort volume qu'on ne modifie jamais. |
Doctrine ORM génère du DDL ((Data Definition Language) InnoDB par défaut. Si une table
existante tourne sous MyISAM, une migration ALTER TABLE ... ENGINE=InnoDB
suffit à la convertir.
ALTERNATIVES
MariaDB et Percona Server : les variantes de MySQL
MySQL officiel n'est pas la seule distribution. MariaDB et Percona Server sont deux variantes majeures, compatibles au niveau du protocole, mais avec des différences importantes à connaître avant de choisir son hébergeur.
| Distribution | Éditeur | Compatibilité MySQL | Particularité |
|---|---|---|---|
| MySQL officiel | Oracle | Référence | Canal LTS et Innovation, support Oracle garanti. Version officielle de MySQL. |
| MariaDB | MariaDB Foundation | Haute mais diverge |
Fork créé en 2009 par Michael Widenius (le créateur originel de MySQL) après le
rachat par Oracle. Diverge de plus en plus depuis MySQL 8.0 : certaines
fonctionnalités récentes ne sont pas portées. Présent sur de nombreux hébergements
mutualisés sous le label "MySQL" : vérifier avec SELECT VERSION().
|
| Percona Server | Percona | 100% compatible | Distribution MySQL avec des patches de performance, des outils de monitoring avancés et Percona XtraBackup pour les sauvegardes à chaud sans downtime. Binaire drop-in compatible avec MySQL officiel. Clever Cloud utilise Percona Server pour son add-on MySQL. |
Source :
Documentation Clever Cloud : add-on MySQL (Percona Server)
. Les dumps SQL (mysqldump) et Doctrine ORM fonctionnent de façon identique
entre MySQL officiel, MariaDB et Percona Server.
BONNES PRATIQUES
Performance MySQL : les bases pour un développeur Symfony
Pas besoin d'être DBA pour éviter les pièges classiques. Ces règles couvrent 90 % des problèmes de performance rencontrés sur des applications Symfony en production.
A faire
Utiliser EXPLAIN avant d'optimiser
EXPLAIN SELECT ... révèle le plan d'exécution : type ALL
signifie un full table scan (mauvais), ref ou range signifie
qu'un index est utilisé (bon). MySQL 8.0+ : EXPLAIN ANALYZE donne les vrais
temps d'exécution mesurés, pas juste le plan estimé.
A faire
Indexer les colonnes utilisées en WHERE et JOIN
Un index manquant force un full table scan sur chaque requête. Les colonnes de clé
étrangère, de filtre (status, type) et de tri
(created_at) doivent systématiquement être indexées. Avec
Doctrine, l'attribut
#[ORM\Index] sur l'entité génère l'index via la migration.
Erreur classique
Le N+1 en Doctrine
Charger 100 entités puis accéder à leur relation en lazy loading génère 101 requêtes
MySQL. Solution : ->leftJoin('u.posts', 'p')->addSelect('p') dans le
QueryBuilder pour charger les relations en une seule requête avec un JOIN.
Erreur classique
Enrober une colonne indexée dans une fonction
WHERE YEAR(created_at) = 2024 empêche l'utilisation de l'index sur
created_at. Réécrire en plage de dates :
WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01'
pour que l'index B-tree soit exploité.
Erreur classique
SELECT * sur des entités volumineuses
Doctrine charge par défaut toutes les colonnes. Sur une liste, utiliser
->select('u.id, u.name') dans le QueryBuilder pour éviter de transférer
des colonnes TEXT ou BLOB inutilement sur chaque ligne.
Erreur classique
LIKE '%texte%' ne peut pas utiliser un index
Un LIKE '%mot%' avec un joker en début de motif force un full table scan.
Pour la recherche textuelle, préférer un index FULLTEXT avec
MATCH AGAINST, ou Blackfire
pour identifier les requêtes problématiques sur un volume réel.
STRATÉGIE D'INDEXATION
Comment choisir, positionner et nettoyer ses index
Un index manquant ralentit les lectures. Un index inutile ralentit les écritures. La bonne stratégie se construit sur les requêtes réelles, pas sur l'intuition.
1. Détecter avec le slow query log
Activer le slow query log pour enregistrer toutes les requêtes dépassant un seuil. C'est la source de vérité : on indexe ce qui est lent en production, pas ce qu'on suppose lent.
-- Activer en session (sans redémarrer MySQL)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 0.5; -- en secondes
SET GLOBAL log_queries_not_using_indexes = 'ON'; L'outil pt-query-digest (Percona Toolkit) agrège le log et liste les requêtes les plus coûteuses en premier.
2. Radiographier avec EXPLAIN
EXPLAIN affiche le plan
d'exécution sans exécuter la requête. La colonne
type révèle si un index est
utilisé.
| type | Lecture |
|---|---|
| const / ref | Index utilisé, peu de lignes lues |
| range | Index sur une plage (BETWEEN, >, <) |
| ALL | Full Table Scan : aucun index utilisé |
EXPLAIN ANALYZE exécute réellement la
requête et affiche les temps mesurés (MySQL 8.0+).
3. Quelles colonnes indexer en priorité
L'ordre de priorité pour les colonnes candidates à l'indexation :
- 1 WHERE : la colonne filtrée est la candidate principale. Plus elle est sélective, plus l'index est efficace.
- 2 JOIN ON : les colonnes de jointure sans index forcent un scan complet de la table jointe.
- 3 ORDER BY : un index sur la colonne de tri évite le tri en mémoire
(
filesortdans EXPLAIN). - ✕ SELECT uniquement : une colonne présente seulement dans le SELECT ne bénéficie pas d'un index.
4. Index composite : la règle du préfixe gauche
Un index composite
(status, created_at) sert les
requêtes qui filtrent sur le préfixe gauche des colonnes.
WHERE status = 'published' utilise l'index WHERE status = 'x' AND created_at > '2025' utilise l'index WHERE created_at > '2025' pas d'index Ordre dans l'index : colonne la plus sélective en premier. Tester avec EXPLAIN ANALYZE sur les données réelles avant de décider.
5. Pas toutes les combinaisons : le coût des index
Chaque index doit être mis à jour à chaque INSERT, UPDATE et DELETE. Un index a un coût en écriture, pas seulement en espace disque. Indexer seulement les requêtes qui apparaissent dans le slow query log ou dans les endpoints critiques mesurés.
Workflow recommandé
- 1. Activer le slow query log en production
- 2. Identifier les requêtes lentes avec pt-query-digest
- 3. EXPLAIN sur chaque requête problématique
- 4.
Ajouter un index ciblé (Doctrine :
#[ORM\Index]) - 5. Vérifier avec EXPLAIN ANALYZE
6. Nettoyer les index inutilisés
MySQL enregistre les statistiques d'utilisation des index dans
performance_schema. La vue
sys.schema_unused_indexes liste
tous les index jamais utilisés depuis le dernier démarrage du serveur.
-- Index jamais utilisés depuis le démarrage
SELECT object_schema, object_name, index_name
FROM sys.schema_unused_indexes
WHERE object_schema = 'ma_base'
ORDER BY object_name;
-- Confirmer le non-usage avec le compteur brut
SELECT object_schema, object_name, index_name, count_star
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE index_name IS NOT NULL
AND count_star = 0
AND object_schema = 'ma_base'
ORDER BY object_name; Précaution : les statistiques sont remises à zéro au redémarrage de MySQL. Observer sur une période représentative (idéalement plusieurs semaines en production) avant de supprimer un index.
Cas particulier : les index UNIQUE ne doivent jamais être supprimés sans vérifier les contraintes d'intégrité, même s'ils n'apparaissent pas dans les lectures.
BONNES PRATIQUES & DOCUMENTATION
Nos conventions MySQL
Documentation de référence pour l'équipe SmartBooster.
Se connecter à MySQL depuis un conteneur Docker
Se connecter à MySQL depuis un conteneur Docker
Dans nos projets Symfony, MySQL tourne dans un conteneur Docker. Pour ouvrir une session MySQL interactive depuis le poste de développement :
# Connexion au conteneur mysql, puis lancement du client MySQL
docker compose exec mysql mysql -u root -p
# Connexion directe en une commande (mot de passe via variable d'environnement)
docker compose exec mysql mysql -u app -papp app
Le troisième argument (app) est le nom de la base de données. Les identifiants sont définis dans le
docker-compose.yml via les variables MYSQL_USER, MYSQL_PASSWORD et MYSQL_DATABASE.
Commandes MySQL utiles au quotidien
Commandes MySQL utiles au quotidien
Une fois connecté au client MySQL, les commandes suivantes couvrent l'essentiel des besoins quotidiens :
| Commande | Explication |
|---|---|
SHOW DATABASES; |
Liste toutes les bases de données accessibles avec l'utilisateur courant |
USE nom_base; |
Sélectionne la base de données active pour les requêtes suivantes |
SHOW TABLES; |
Liste les tables de la base de données active |
DESCRIBE nom_table; |
Affiche la structure d'une table (colonnes, types, clés, valeurs par défaut) |
SHOW CREATE TABLE nom_table\G |
Affiche le DDL complet de la table, utile pour auditer les index |
SHOW FULL PROCESSLIST; |
Liste les requêtes en cours d'exécution, pour identifier les requêtes bloquantes |
SHOW STATUS LIKE 'Slow%'; |
Compteurs de requêtes lentes depuis le démarrage du serveur |
Analyser les requêtes lentes avec EXPLAIN
Analyser les requêtes lentes avec EXPLAIN
EXPLAIN est la commande clé pour diagnostiquer les problèmes de performance. Elle affiche le plan
d'exécution choisi par l'optimiseur MySQL pour une requête donnée.
EXPLAIN SELECT * FROM commande WHERE client_id = 42 AND statut = 'en_cours';
Les colonnes à surveiller en priorité :
- type :
ALLsignifie un full table scan (problème).ref,rangeouconstindiquent qu'un index est utilisé. - key : nom de l'index utilisé.
NULL= pas d'index = problème. - rows : estimation du nombre de lignes scannées. Plus ce chiffre est proche du résultat attendu, mieux c'est.
- Extra :
Using filesortouUsing temporarysont des signaux de requêtes à optimiser.
EXPLAIN ANALYZE (MySQL 8.0+) exécute réellement la requête et retourne les temps d'exécution réels
par étape, beaucoup plus précis que l'estimation de EXPLAIN seul.
Gestion des dumps SQL
Gestion des dumps SQL
Exporter une base de données (depuis le conteneur) :
docker compose exec mysql mysqldump -u root -p app > dump.sql
Exporter uniquement la structure (sans les données) :
docker compose exec mysql mysqldump -u root -p --no-data app > structure.sql
Restaurer un dump dans un conteneur :
docker compose exec -T mysql mysql -u root -p app < dump.sql
Le flag -T (sans TTY) est nécessaire pour la redirection stdin dans docker compose exec.
Commandes Doctrine au quotidien (Symfony)
Commandes Doctrine au quotidien (Symfony)
Les migrations de schéma passent par Doctrine et non par MySQL directement. Les commandes bin/console
à connaître :
# Générer une migration depuis les changements d'entités PHP
php bin/console doctrine:migrations:diff
# Appliquer les migrations en attente (à lancer avant chaque mise en production)
php bin/console doctrine:migrations:migrate
# Voir le statut des migrations (lesquelles sont appliquées, lesquelles sont en attente)
php bin/console doctrine:migrations:status
# Valider que le schéma en base correspond aux entités PHP (pratique en CI)
php bin/console doctrine:schema:validate
En développement local, doctrine:schema:update --force peut être utilisé pour synchroniser
rapidement le schéma sans passer par les migrations. En environnement de recette ou production,
utiliser exclusivement doctrine:migrations:migrate.
Requête pour avoir la taille des bases de données
Requête pour avoir la taille des bases de données
SELECT
table_schema AS "Base de données",
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS "Taille (Mo)"
FROM
information_schema.TABLES
GROUP BY
table_schema
ORDER BY
SUM(data_length + index_length) DESC;
Pour aller plus loin
Documentation utile
Référence complète MySQL 9.7 LTS : Hypergraph optimizer, JavaScript UDF, JSON duality et PGO.
Référence complète MySQL 8.4 LTS : SQL, InnoDB, réplication, sécurité et performance.
Dates de fin de support par version MySQL, mises à jour automatiquement par la communauté.
Pour aller plus loin
Approfondir votre réflexion
Doctrine ORM mappe les entités PHP sur MySQL et génère les migrations de schéma. Relations, index, DQL et bonnes pratiques de performance documentés sur la page dédiée.
MySQL tourne dans un conteneur Docker sur tous nos projets. Notre stack symfony-docker intègre MySQL 8.4 avec un volume nommé pour la persistance des données.
Symfony fournit le framework au-dessus de MySQL et Doctrine ORM. Les migrations Doctrine versionnent les évolutions de schéma directement dans Git.
MySQL equipe nos logiciels métier sur mesure : de la TPE avec quelques milliers de lignes aux plateformes à fort volume avec indexation avancée.
Vous avez un projet ?
Contactez-nous pour savoir comment nous pouvons vous aider.