← Retour aux articles
Performance et bases de données

Index de base de données : les super-héros invisibles de votre application. Expliqué simplement avec du code Laravel et des avertissements importants

Un guide clair des index de base de données avec des exemples Laravel : comment ils fonctionnent, quand les ajouter et les avertissements critiques que chaque développeur doit connaître sur les index composites, à faible sélectivité et inutilisés.

✦
Article en vedette ↗

Index de base de données : les super-héros invisibles de votre application. Expliqué simplement avec du code Laravel et des avertissements importants

Imaginez que vous cherchiez un mot précis dans un livre de 1 000 pages — mais que le livre n'ait ni table des matières ni index à la fin. Vous devriez lire chaque page. C'est exactement ce que fait votre base de données lorsqu'elle exécute une requête sur une colonne sans index.

Les index sont les super-héros invisibles de votre application. Quand ils font leur travail, personne ne le remarque. Quand ils manquent, tout s'arrête. Décomposons ce qu'ils sont, comment ils fonctionnent et — surtout — les avertissements que chaque développeur doit connaître.

📚 Qu'est-ce qu'un index de base de données ?

Un index de base de données est une structure de données spéciale (généralement un B-tree) que la base de données maintient aux côtés des données de votre table. Il stocke une copie triée d'une ou plusieurs colonnes, plus des pointeurs vers les lignes d'origine.

Voyez-le comme l'index alphabétique à la fin d'un manuel : au lieu de parcourir chaque page, vous sautez directement à l'entrée pertinente.

🎯 Pourquoi les index sont importants

  • Accélèrent les clauses WHERE — trouver des lignes par une condition devient O(log n) au lieu de O(n).
  • Accélèrent les opérations JOIN — les clés étrangères bénéficient énormément des index.
  • Accélèrent ORDER BY — si le tri correspond à un index, aucun tri supplémentaire n'est nécessaire.
  • Garantissent l'unicité — les index uniques garantissent l'intégrité des données au niveau du stockage.

Sans index, MySQL/PostgreSQL doit effectuer un balayage complet de la table. Sur une table de plusieurs millions de lignes, c'est la différence entre 5 ms et 5 secondes.

🛠 Créer des index dans Laravel

Le système de migrations de Laravel rend la création d'index propre et expressive.

1. Index sur une seule colonne :

Schema::table('users', function (Blueprint $table) { $table->index('email'); // Index simple });

2. Index unique :

Schema::table('users', function (Blueprint $table) { $table->unique('email'); // Garantit l'unicité });

3. Index composite (plusieurs colonnes) :

Schema::table('orders', function (Blueprint $table) { $table->index(['user_id', 'created_at']); // Index composite });

4. Index avec un nom personnalisé :

Schema::table('posts', function (Blueprint $table) { $table->index('status', 'idx_posts_status'); });

5. Clé étrangère avec index automatique :

Schema::table('posts', function (Blueprint $table) { $table->foreignId('user_id')->constrained(); // Crée un index automatiquement });

🔍 Comment vérifier qu'un index est utilisé

Utilisez EXPLAIN pour voir le plan d'exécution :

EXPLAIN SELECT * FROM users WHERE email = 'user@example.com'; -- Sortie (index utilisé) : -- Index Scan using users_email_index on users (cost=0.43..8.45 rows=1 width=...) -- Index Cond: ((email)::text = 'user@example.com'::text) -- Sortie (pas d'index, scan complet) : -- Seq Scan on users (cost=0.00..1500.00 rows=1 width=...) -- Filter: ((email)::text = 'user@example.com'::text)

Dans Laravel :

$plan = DB::select('EXPLAIN SELECT * FROM users WHERE email = ?', ['user@example.com']); dd($plan);

Cherchez Index Scan ou Index Only Scan — bon. Cherchez Seq Scan — mauvais, sauf si la table est minuscule.

⚠️ Avertissements importants que chaque développeur doit connaître

1. Les index ralentissent les écritures

Chaque INSERT, UPDATE et DELETE doit également mettre à jour chaque index de cette table. Une table avec 10 index effectue les écritures environ 10 fois plus lentement qu'une table sans index. Indexez uniquement les colonnes que vous interrogez, pas celles que vous imaginez pouvoir interroger.

2. La règle du « préfixe le plus à gauche » pour les index composites

Un index sur (a, b, c) peut être utilisé pour des requêtes sur a, (a, b) ou (a, b, c). Il ne peut pas être utilisé efficacement pour des requêtes sur b seul ou (b, c). L'ordre compte.

// Ceci utilise l'index composite (user_id, created_at) : SELECT * FROM orders WHERE user_id = 5 AND created_at > '2024-01-01'; // Ceci ne l'utilise PAS efficacement : SELECT * FROM orders WHERE created_at > '2024-01-01';

3. Les index sur des colonnes à faible sélectivité sont inutiles

Une colonne booléenne avec 99 % de true et 1 % de false est un mauvais candidat à l'indexation. L'optimiseur l'ignorera souvent et effectuera un scan complet de toute façon, car scanner l'index plus rechercher les lignes coûte plus cher que simplement scanner la table.

4. Les fonctions sur les colonnes indexées tuent l'index

// MAUVAIS — l'index sur `email` n'est PAS utilisé : SELECT * FROM users WHERE LOWER(email) = 'user@example.com'; // BON — l'index sur `email` EST utilisé : SELECT * FROM users WHERE email = 'user@example.com';

Solutions : stockez des données normalisées, ou utilisez des index fonctionnels/expressionnels (PostgreSQL les prend en charge ; MySQL 8+ aussi).

5. Trop d'index, c'est aussi mauvais que pas assez

Chaque index prend de l'espace disque et ralentit les écritures. Plus important encore, l'optimiseur doit considérer plus d'options lors de la planification d'une requête, ce qui peut conduire à de mauvaises décisions. Auditez vos index régulièrement.

6. Les index inutilisés sont un pur surcoût

Trouvez les index qui ne sont jamais utilisés et supprimez-les. Dans PostgreSQL :

SELECT schemaname, relname AS table_name, indexrelname AS index_name, idx_scan AS times_used FROM pg_stat_user_indexes WHERE idx_scan = 0 ORDER BY pg_relation_size(indexrelid) DESC;

Dans MySQL :

SELECT * FROM sys.schema_unused_indexes;

7. La sélectivité de l'index est plus importante que le nombre d'index

Un index est plus précieux lorsqu'il filtre jusqu'à une petite fraction des lignes. Une requête qui renvoie 1 % d'une table en bénéficie énormément. Une requête qui renvoie 80 % ne le fait pas — la base de données scannera probablement la table à la place.

🚀 Un scénario d'optimisation Laravel réaliste

Considérez une application e-commerce avec une page lente « commandes récentes pour l'utilisateur » :

// Requête lente $orders = Order::where('user_id', $user->id) ->orderByDesc('created_at') ->take(20) ->get();

Sur une table de 5 millions de commandes, cette requête pourrait prendre des secondes. Ajoutez un index composite :

Schema::table('orders', function (Blueprint $table) { $table->index(['user_id', 'created_at']); });

Maintenant, la même requête s'exécute en quelques millisecondes, car l'index fournit à la fois le filtre et l'ordre de tri.

📊 Aide-mémoire des index

  • Clés étrangères → toujours indexer.
  • Colonnes fréquemment filtrées → indexer si sélectives.
  • Colonnes de tri dans ORDER BY → indexer si souvent utilisées.
  • Colonnes à faible sélectivité (booléens, statuts avec peu de valeurs) → généralement à éviter.
  • Ordre dans un index composite → colonnes les plus sélectives / les plus utilisées en premier, en suivant la règle du préfixe le plus à gauche.
  • Auditez régulièrement → supprimez les index inutilisés ; ils coûtent plus qu'ils ne rapportent.

💡 Conseils pratiques

  1. Commencez par les clés étrangères. Ce sont les index avec le meilleur ROI que vous ajouterez jamais.
  2. Mesurez avant et après. Utilisez EXPLAIN ANALYZE pour confirmer l'amélioration.
  3. Testez avec des données de taille production. Une table de test de 1 000 lignes ne révélera jamais un problème d'index.
  4. Surveillez le chemin d'écriture. Si les insertions ralentissent, l'un de vos index est peut-être le coupable.
  5. Préférez moins d'index composites bien choisis à de nombreux index à une seule colonne.
  6. N'indexez pas au hasard. Indexez ce dont le planificateur de requêtes a réellement besoin.

🔗 Conclusion

Les index sont le moteur silencieux des applications hautes performances. Ils transforment des requêtes qui rampent en recherches instantanées, protègent votre base de données contre une charge incontrôlée et soutiennent discrètement chaque page rapide que vos utilisateurs voient.

Mais ils ne sont pas gratuits. Chaque index est un échange : vitesse de lecture contre coût d'écriture et espace disque. Ajoutez-les délibérément, vérifiez qu'ils sont utilisés et nettoyez ceux qui ne le sont pas. Maîtrisez cette discipline, et votre application évoluera — élégamment, invisiblement et à grande vitesse.

Technologies et sujets

Tags de l'article

Aucun article ne correspond à ces filtres.

Vous avez un projet ou une idée à discuter ?

Parlons-en ↗