Les développeurs me posent souvent la même question : « Mon API est lente. Par où commencer ? » Le réflexe est généralement de mettre à niveau le serveur ou de doubler la RAM. Cela coûte de l'argent et résout rarement la cause profonde. Dans la plupart des applications Laravel, le goulot d'étranglement se situe au niveau de la couche de base de données. La syntaxe élégante du framework facilite l'oubli du fait que chaque appel Eloquent devient finalement du SQL, et que le SQL est souvent là où les problèmes commencent.
Avant de toucher aux paramètres du serveur, examinez vos requêtes de manière méthodique.
Commencez par le bon diagnostic
N'optimisez pas à l'aveugle. Réécrire des requêtes au hasard n'est que de la conjecture, et la conjecture fait perdre des heures.
Vous devez identifier les instructions qui consomment le plus de temps total. Observez votre application sous une charge réelle. Laravel Telescope vous offre une vue claire de chaque requête exécutée lors d'une requête, avec le temps d'exécution associé. Laravel Debugbar les affiche dans votre navigateur lors du développement local afin que vous puissiez repérer immédiatement les anomalies. Lorsque vous devez détecter des problèmes en production, activez le MySQL Slow Query Log. Il enregistre les instructions qui dépassent un seuil que vous définissez, ce qui le rend idéal pour trouver des surprises qui n'apparaissent pas dans les petits jeux de données. Si vous exécutez quelque chose de plus important, un outil de monitoring des performances applicatives peut corréler les points de terminaison HTTP lents avec des appels de base de données spécifiques.
En examinant les données, recherchez deux choses : le temps d'exécution absolu et la fréquence d'appel. Une requête prenant quarante millisecondes semble inoffensive jusqu'à ce que vous réalisiez qu'elle s'exécute deux mille fois par minute. Un rapport de trois secondes qui s'exécute une fois par heure peut être moins important qu'une recherche d'une demi-seconde qui s'exécute sur chaque page. Réglez d'abord les problèmes à fort impact.
Arrêtez de tout demander
SELECT * est pratique. C'est aussi coûteux. Lorsque vous écrivez Model::all() ou que vous récupérez un ensemble de résultats sans nommer les colonnes, MySQL transporte chaque champ pour chaque ligne correspondante. Cela inclut les champs de texte volumineux, les blobs JSON et tout autre élément présent dans la table. L'ensemble de résultats s'agrandit, l'utilisation de la mémoire grimpe et le temps passé à sérialiser la réponse augmente.
Soyez explicite. Si votre contrôleur n'a besoin que des champs id, name et email, demandez exactement ceux-là :
User::select('id', 'name', 'email')->get();
Dans le query builder, le même principe s'applique. Des charges utiles plus petites circulent plus rapidement sur le réseau et consomment moins de RAM sur votre serveur d'application. C'est l'un des gains les plus simples à obtenir, et pourtant, il est facile de l'ignorer car Laravel fait de SELECT * le comportement par défaut.
Laissez EXPLAIN guider vos modifications
Ne refactorisez jamais une requête lente sans exécuter EXPLAIN au préalable. Dans MySQL, le mot-clé EXPLAIN affiche le plan d'exécution de la requête. Il révèle exactement comment l'optimiseur a l'intention de trouver vos données.
Prêtez attention à la colonne type. Si vous voyez ALL, MySQL effectue un balayage complet de la table (full table scan). Cela signifie qu'il lit chaque ligne pour satisfaire votre clause WHERE. Regardez la colonne key pour voir si l'optimiseur utilise un index ou non. Ensuite, vérifiez la colonne Extra. Si vous repérez Using temporary ou Using filesort, MySQL construit des tables intermédiaires ou effectue un tri en mémoire parce que votre structure actuelle ne peut pas satisfaire la requête proprement.
Exécutez EXPLAIN dans votre client MySQL, ou utilisez un outil qui formate la sortie pour vous. Une fois que vous voyez le plan, vous savez si le problème est un index manquant, une mauvaise jointure ou un prédicat que le moteur ne peut pas optimiser. Plus besoin de deviner.
Indexez avec intention
Les index sont l'outil le plus puissant pour accélérer les recherches, mais ils ne fonctionnent que s'ils correspondent à votre manière de requêter. Sans l'index approprié, MySQL parcourt les lignes une par une. Cela peut sembler acceptable en développement sur une table de mille lignes, puis s'effondrer en production sur une table de dix millions de lignes.
Commencez par des index sur une seule colonne pour les champs qui apparaissent fréquemment dans les clauses WHERE. Si vous filtrez constamment par status, ajoutez un index sur status.
Lorsqu'une requête filtre sur plusieurs colonnes simultanément, passez aux index composites. L'ordre des colonnes à l'intérieur de l'index est important car MySQL lit les index composites de gauche à droite. C'est ce qu'on appelle la règle du préfixe le plus à gauche (leftmost prefix rule). Si votre requête recherche par user_id puis trie par created_at, un index composite sur (user_id, created_at) aide considérablement. Inversez l'ordre et l'optimiseur pourrait ne pas utiliser l'index pour le filtre du tout.
N'indexez pas toutes les colonnes. Chaque index ajoute une surcharge aux insertions, aux mises à jour et aux suppressions car MySQL doit maintenir la structure. Ajoutez-les délibérément en fonction des modèles que vous avez identifiés lors de vos mesures.
Éloignez les fonctions des colonnes
Cette erreur désactive silencieusement les index. Lorsque vous enveloppez une colonne dans une fonction au sein d'une clause WHERE, MySQL ne peut pas
