Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

Lire un plan de requête avec EXPLAIN

Après cette leçon: Je peux lire un plan avec EXPLAIN et dire pourquoi une requête coûte moins cher qu'une autre.

Leçon de 60 minAucune commande

Voir ce que le moteur fait d'une requête

Un plan de requête est la liste des étapes que le moteur suit pour répondre : lire les tables, filtrer, relier, additionner. La commande explain l'affiche sans exécuter la requête.

Deux étudiants écrivent la même question de deux façons. Le plan dit si DuckDB fait vraiment un travail différent.

À la fin de cette leçon

Remarque

Je peux lire un plan avec EXPLAIN et dire pourquoi une requête coûte moins cher qu'une autre.

Mots clés

MotCe que ça veut direExemple
Plan de requêteles étapes que le moteur suit pour répondre
EXPLAINaffiche le plan sans exécuter la requête
Lecture (scan)l'étape qui lit une tableSeq Scan
Filtrel'étape qui garde seulement certaines lignes
Optimiseurla partie du moteur qui choisit le plan

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Un plan se lit de bas en haut

Un plan est une pile de boîtes. Les données entrent par les boîtes du bas, qui lisent les tables, et remontent vers celle du haut, qui donne le résultat.

Chaque boîte porte un nom : lecture, filtre, jointure, agrégat. Les noms exacts changent un peu d'une version à l'autre.

Exemple : les boîtes d'un plan DuckDB

Nom affichéCe que fait la boîteÉtape de la requête
Seq ScanLit une table, avec ses colonnes et parfois un filtrefrom
FilterGarde les lignes qui réussissent un testwhere, qualify
Hash JoinRelie deux entrées sur une cléjoin ... on
Hash Group ByRegroupe et additionnegroup by, sum
WindowCalcule une fonction de fenêtreover (...)
ProjectionGarde ou calcule des colonnesselect

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

À vous : lire le plan d'une jointure

Code: duckdb
-- Le plan d'une jointure suivie d'un total. Lisez-le de bas en haut.
explain
select clients.nom, sum(commandes.montant) as total
from clients
join commandes on commandes.client_id = clients.id
where commandes.annee = 2026
group by clients.nom;
-- Cherchez la boîte Seq Scan de commandes : quelle ligne mentionne annee = 2026 ?

Filtrer tôt réduit le travail

Une jointure compare des lignes. Moins il y a de lignes à relier, moins le travail est grand.

Si on veut seulement les commandes de 2026, mieux vaut les garder avant la jointure que de relier toutes les années puis de jeter.

Exemple : les lignes à relier

VersionCommandes envoyées à la jointureLignes jetées après
Relier d'abord, filtrer ensuite83
Filtrer d'abord, relier ensuite50

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

À vous : le filtre écrit avant la jointure

Code: duckdb
-- Le même calcul, avec le filtre écrit avant la jointure.
explain
with recentes as (
  select client_id, montant from commandes where annee = 2026
)
select clients.nom, sum(recentes.montant) as total
from clients
join recentes on recentes.client_id = clients.id
group by clients.nom;
-- Comparez ce plan à celui du bloc précédent : voyez-vous une différence de forme ?

Une erreur fréquente

Attention

Beaucoup pensent que réécrire une requête change toujours son plan. L'optimiseur de DuckDB descend souvent le filtre tout seul : ici, les deux écritures ont la même forme. Lisez le plan avant de réécrire, et réécrivez pour la clarté d'abord.

Certains filtres ne peuvent pas descendre

Un filtre sur une colonne d'une table peut descendre jusqu'à la lecture. Un filtre sur le résultat d'un calcul ne le peut pas : il faut avoir calculé avant.

C'est le cas du rang d'une fenêtre. La boîte Filter reste au-dessus de Window, qui reste au-dessus de Hash Group By.

À vous : le plan d'un filtre de rang

Code: duckdb
-- Un filtre sur un rang : il ne peut pas descendre sous la fenêtre.
explain
select nom, total, rank() over (order by total desc) as rang
from (
  select clients.nom, sum(commandes.montant) as total
  from clients join commandes on commandes.client_id = clients.id
  group by clients.nom
)
qualify rang <= 2;
-- Dans quel ordre, de bas en haut, voyez-vous Hash Group By, Window et Filter ?

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.