SQL avancĂ© : comment optimiser tes requĂȘtes et gagner des secondes sur chaque appel
Tu as Ă©crit ton premier SELECT *, tu maĂźtrises les jointures simples, et pourtant ton application ralentit dĂšs que la base dĂ©passe quelques milliers de lignes. Ce n’est pas ta faute : SQL est un langage puissant, mais il rĂ©compense ceux qui comprennent ce qui se passe derriĂšre la syntaxe. Index, plans d’exĂ©cution, jointures efficaces â ces notions sĂ©parent un dĂ©veloppeur qui colle des requĂȘtes d’un dĂ©veloppeur qui construit des applications rapides.
Pourquoi un SELECT peut devenir lent sans raison apparente
Le moteur de base de donnĂ©es ne lit pas tes lignes un par une comme un humain. Il utilise des structures internes â des arborescences, des hash maps, des scans sĂ©quentiels â et il choisit la stratĂ©gie selon des statistiques que tu ne vois pas directement. Quand tu fais un SELECT * FROM users WHERE email = 'a@b.com' sans index sur email, le moteur doit parcourir toute la table. Sur 10 000 lignes, c’est instantanĂ© Ă l’Ćil humain. Sur 10 millions, c’est une catastrophe.
Le premier rĂ©flexe : ajouter un index. Mais pas n’importe comment. Un index est un coĂ»t mĂ©moire et un coĂ»t d’Ă©criture. Chaque INSERT ou UPDATE doit mettre Ă jour l’index. Tu ne veux pas indexer chaque colonne â tu veux indexer celles que tu interroges souvent, et dans l’ordre de tes clauses WHERE et ORDER BY.
Les index que tu dois connaĂźtre
- B-Tree (l’index classique) â parfait pour les Ă©galitĂ©s et les intervalles (
BETWEEN,<,>). C’est celui que crĂ©eCREATE INDEXpar dĂ©faut. - Hash â excellent pour les Ă©galitĂ©s exactes, mais inutile pour les plages.
- Partial index â un index uniquement sur les lignes qui rĂ©pondent Ă une condition (
WHERE statut = 'actif'). RĂ©duit la taille et accĂ©lĂšre les requĂȘtes ciblĂ©es. - Composite (multi-colonnes) â un index sur
(a, b, c)sert aussiWHERE a = ?etWHERE a = ? AND b = ?, mais pasWHERE b = ?seul.
RĂšgle pratique : si tu interroges rĂ©guliĂšrement avec WHERE user_id = ? AND created_at > ?, crĂ©e l’index sur (user_id, created_at) â pas l’inverse. L’ordre compte : la premiĂšre colonne doit ĂȘtre celle avec la sĂ©lection la plus restrictive.
Lire un plan d’exĂ©cution sans paniquer
Avant d’optimiser aveuglĂ©ment, demande au moteur de te raconter ce qu’il fait. En PostgreSQL : EXPLAIN ANALYZE SELECT .... En MySQL : EXPLAIN FORMAT=JSON SELECT .... Tu verras des lignes comme Seq Scan (mauvais â scan complet) ou Index Scan (bon). Un Nested Loop avec un grand nombre de lignes cĂŽtĂ© droit est un signal d’alerte.
Le but n’est pas d’Ă©liminer tout Seq Scan â certaines requĂȘtes font effectivement le tour entier de la table. Le but est de savoir pourquoi le moteur a fait ce choix. Si ton index n’est pas utilisĂ©, c’est souvent parce que la table est trop petite pour que l’index vienne en aide (le moteur estime que le scan est plus rapide), ou parce que le type de donnĂ©e ne correspond pas (comparaison sur du texte avec un index numĂ©rique).
Jointures : moins n’est pas toujours plus
Le piĂšge classique : faire 5 jointures pour rĂ©cupĂ©rer des donnĂ©es qui pourraient ĂȘtre dans une seule table, ou au contraire charger 20 colonnes d’une table liĂ©e alors que tu n’en utilises que 3. En SQL, chaque colonne demandĂ©e doit ĂȘtre justifiĂ©e. Un SELECT * est un luxe qui coĂ»te la mĂ©moire rĂ©seau, la mĂ©moire du serveur, et le temps d’analyse.
Pour les jointures, privilĂ©gie les clĂ©s de jointure indexĂ©es, et veille au type : rejoindre un INT avec un VARCHAR force le moteur Ă convertir â et l’index devient inutilisable. Corrige le schĂ©ma, pas la requĂȘte.
Cinq rĂšgles que j’applique Ă chaque projet
- Ne jamais faire
SELECT *en production â nommer chaque colonne. - CrĂ©er des index composĂ©s dans l’ordre des clauses
WHERE. - Lire le plan d’exĂ©cution avant de modifier quoi que ce soit.
- Limiter avec
LIMIT+OFFSETcorrectement (Ă©viter les grands offsets â prĂ©fĂ©rerWHERE id > ?). - VĂ©rifier avec des donnĂ©es rĂ©alistes, pas un jeu de 10 lignes.
Ces rĂšgles semblent simples, mais elles sont souvent ignorĂ©es parce qu’elles demandent un peu de discipline au dĂ©part. Le rĂ©sultat : des applications qui rĂ©pondent en millisecondes mĂȘme avec des bases de plusieurs millions d’enregistrements.
Et maintenant ?
Si tu veux aller plus loin â comprendre comment un moteur passe de la syntaxe SQL Ă un arbre d’opĂ©rations, et comment choisir entre un index B-Tree et un index GIN sur du JSON â c’est exactement le genre de sujet que je traite dans les cours Python et bases de donnĂ©es. Pas de thĂ©orie abstraite : on travaille sur une vraie base, on examine des vrais plans d’exĂ©cution, et on corrige des requĂȘtes qui ralentissent un projet rĂ©el.
Tu peux aussi commencer par un cours particulier : un Ă©change ciblĂ© sur ton projet actuel, avec un diagnostic rapide de tes requĂȘtes et des recommandations concrĂštes. Je propose des forfaits adaptĂ©s â de 1h au coaching sur plusieurs semaines.