Index
Progression
#Indexes
Accélèrent la recherche au prix d'espace et de coûts d'écriture. Ils servent surtout aux clauses WHERE
, JOIN
et tri.
Objectifs d’apprentissage
- Concevoir des index utiles: colonnes filtrantes, ordre (égalité → range), couverture.
- Comprendre SARGability: écrire des prédicats indexables et éviter les fonctions sur colonnes.
- Mesurer les compromis: espace, coût d’insertion/MAJ, maintien de la statistique.
1create table t(id int, x int);2insert into t values (1,10),(2,20),(3,30);3create index if not exists idx_t_x on t(x);4-- La requête peut utiliser l'index sur x5select * from t where x >= 20;
Note: Dans SQLite en WASM, on ne peut pas inspecter facilement le plan d’exécution, mais le principe reste valable.
#Règles pratiques (SARGability)
- Éviter les fonctions sur la colonne indexée côté gauche:
where date(ts) = '2024-09-01'
empêche l’index. Préférer des bornes:where ts >= '2024-09-01' and ts < '2024-09-02'
. LIKE 'prefix%'
utilise un index;LIKE '%suffix'
non (sauf index spécialisés).- Casts implicites peuvent casser l’index (ex: comparer
int
àtext
). Harmoniser les types. - Conditions combinées sur (a,b): l’index
(a,b)
aide poura=?
eta=? and b between ...
; l’ordre compte.
#Index composites et couverture
- Ordre des colonnes: placez d’abord celles testées par égalité (
=
ouIN
), puis range (>
/<
/BETWEEN
), puis tri (ORDER BY
). - Index couvrant: inclure toutes les colonnes lues (selon moteur: colonnes incluses) pour éviter les lookups.
- Sélectivité: privilégier les colonnes très discriminantes (haute cardinalité) pour maximiser le gain.
Chaque INSERT/UPDATE/DELETE
met à jour les index concernés. Trop d’index ralentissent l’écriture et les migrations; supprimez ceux non utilisés.
#Quand ne pas indexer
- Colonnes à faible cardinalité (peu de valeurs distinctes) utilisées seules dans
WHERE
(ex.: booléen) — peu sélectif; combinez avec d’autres colonnes ou index partiels. - Tables toutes petites — le scan séquentiel est souvent plus rapide et plus simple.
- Colonnes très souvent mises à jour si l’index n’apporte pas de gain réel.
#Types d’index (aperçu)
- B‑Tree: par défaut, efficace pour égalité et plages ordonnées; supporte
ORDER BY
. - Hash: égalité seulement (selon moteur); pas d’ordre.
- GIN/GiST (PostgreSQL): pour documents, tableaux, recherche plein‑texte, géo. Choisir selon le type et les opérateurs.
#Statistiques et plans
Les moteurs s’appuient sur des statistiques (histogrammes, NDV). Des stats obsolètes peuvent conduire à des plans sous‑optimaux. Exécutez l’analyse/ANALYZE
périodiquement si votre moteur le requiert.
#Playground
#Quiz éclair
- Laquelle de ces clauses favorise l’usage d’un index
(ts)
?
where date(ts) = '2025-01-01'
where ts >= '2025-01-01' and ts < '2025-01-02'
where strftime('%Y', ts) = '2025'
Réponse: bornes sur ts
(seconde option).
#Animation: recherche via B-Tree (concept)
#Pas‑à‑pas: couvrant vs lookup
(a)
permet de localiser rapidement les lignes pour where a=?
ou a>=
…#Mini‑lab: ordre des colonnes d’un index composite
Objectif: essayer des requêtes du type where user_id=? and created_at between ... order by created_at
.
- Créez un index
(created_at, user_id)
et observez les requêtes qui en tirent parti ou non. - Inversez l’ordre
(user_id, created_at)
et comparez LA compatibilité avec égalité→plage→tri.
Placez d’abord les colonnes testées par égalité, puis celles en plage, puis celles utilisées au tri. Les prédicats doivent être SARGables (pas de fonction sur colonne).
#Exercice : Comparaison de performances avec et sans index
Comparez les performances de requêtes SQL avec et sans index sur une table de grande taille.
#Instructions
- Créez une table avec un grand nombre d'enregistrements.
- Exécutez une requête de recherche sans index et mesurez le temps.
- Créez un index approprié et réexécutez la même requête.
- Comparez les performances et expliquez les différences.
#Exemple de requête
1-- Création d'une table de test avec beaucoup de données2create table test_performance(id int, name text, category int);3 4-- Insertion de données de test (simulation)5WITH RECURSIVE6 cnt(x) AS (7 SELECT 18 UNION ALL9 SELECT x+1 FROM cnt10 LIMIT 1000011 )12INSERT INTO test_performance 13SELECT x, 'Name' || x, x % 100 FROM cnt;14