Quelle est la différence entre une requête corrélée et une requête non corrélée  ?

Par :

,le

En SQL, toutes les sous-requêtes ne fonctionnent pas de la même façon selon leur relation avec la requête externe. Certaines s’exécutent une seule fois et transmettent un résultat fixe à la requête principale. D’autres s’exécutent une fois par ligne traitée par la requête externe, en adaptant leur résultat à chaque ligne. Cette distinction porte un nom précis : on parle de sous-requête non corrélée et de sous-requête corrélée. Comprendre cette différence est essentiel pour écrire des requêtes performantes et choisir la bonne approche selon le contexte.

Qu’est-ce qu’une sous-requête non corrélée ?

Une sous-requête non corrélée est entièrement indépendante de la requête externe qui la contient. Elle ne fait référence à aucune colonne de la requête principale et peut s’exécuter seule sans contexte extérieur. Le moteur SQL l’évalue une seule fois, puis transmet son résultat à la requête externe comme une valeur statique. Ce comportement la rend généralement plus rapide qu’une sous-requête corrélée sur de grands volumes de données. C’est la forme la plus courante de sous-requête pour les développeurs qui débutent avec les requêtes imbriquées.

On souhaite afficher tous les employés dont le salaire dépasse le salaire moyen calculé sur l’ensemble de la table.

SELECT nom, salaire
FROM employes
WHERE salaire > (SELECT AVG(salaire) FROM employes);

La sous-requête calcule une seule fois la moyenne globale des salaires, indépendamment de chaque ligne traitée. La requête externe compare ensuite chaque salaire individuel à cette valeur fixe retournée en amont. Si la table est vide, AVG retourne NULL et aucune ligne ne sera sélectionnée par la requête principale.

Qu’est-ce qu’une sous-requête corrélée ?

Une sous-requête corrélée fait référence à au moins une colonne appartenant à la requête externe qui la contient. Cette dépendance oblige le moteur SQL à réévaluer la sous-requête pour chaque ligne traitée par la requête principale. On désigne parfois cette technique par les termes sous-requête liée ou sous-requête imbriquée dépendante dans certaines documentations. Elle correspond logiquement à deux boucles imbriquées : pour chaque ligne externe, la sous-requête interne s’exécute à nouveau. Ce mécanisme est plus coûteux en performance, mais indispensable quand le résultat dépend de la valeur de chaque ligne courante.

On veut afficher chaque employé avec le nombre de commandes qu’il a personnellement traitées dans la table commandes.

SELECT e.nom,
    (SELECT COUNT(*)
     FROM commandes c
     WHERE c.id_employe = e.id_employe) AS nb_commandes
FROM employes e;

La sous-requête corrélée est exécutée une fois par ligne de la table employes, en utilisant la valeur e.id_employe de la ligne courante. Elle retourne un comptage différent pour chaque employé, ce qui est impossible avec une sous-requête non corrélée. COUNT(*) retourne 0 si aucune commande n’est associée à l’employé, jamais NULL.

La différence clé : l’alias de table externe

Ce qui distingue techniquement les deux types est la présence d’un alias de table externe dans la sous-requête. Dans une requête corrélée, cet alias (e.id_employe dans l’exemple précédent) crée le lien entre les deux niveaux d’exécution. Sans cet alias, la sous-requête devient non corrélée et s’exécute une seule fois pour toute la requête. Repérer cet alias dans le code est donc la méthode la plus rapide pour identifier le type de sous-requête. C’est aussi le premier élément à vérifier lors du débogage d’une requête imbriquée complexe.

Impact sur les performances

Une sous-requête non corrélée est calculée une seule fois, ce qui la rend efficace quelle que soit la taille de la table. Une sous-requête corrélée multiplie les opérations : sur une table de 10 000 lignes, elle s’exécute 10 000 fois successivement. Dans ce cas, réécrire la requête avec une jointure ou une CTE (WITH) est souvent plus performant à grande échelle. Cependant, certaines logiques métier ne peuvent s’exprimer qu’avec une sous-requête corrélée, notamment avec EXISTS. Il est donc important de mesurer le plan d’exécution avec EXPLAIN avant d’optimiser une requête corrélée en production.

Tableau comparatif

CritèreNon corréléeCorrélée
Dépendance à la requête externeAucuneRéférence une colonne externe
Nombre d’exécutionsUne seule foisUne fois par ligne traitée
PerformanceRapidePeut être lente sur grands volumes
Testable seuleOuiNon (dépend du contexte externe)
Cas d’usage typiqueValeur ou liste statiqueCalcul ligne par ligne
Alternative possibleRarement nécessaireJOIN ou CTE souvent plus performant

Quand utiliser l’une ou l’autre ?

Privilégiez une sous-requête non corrélée quand la valeur de référence ne dépend pas de la ligne en cours de traitement. Optez pour une sous-requête corrélée uniquement quand chaque ligne nécessite un calcul propre basé sur ses propres valeurs. Si vous utilisez EXISTS pour tester l’existence d’une ligne liée, la corrélation est inévitable et pleinement justifiée. Pour toute autre situation, envisagez d’abord une jointure  ou une CTE afin de préserver les performances de votre requête. La règle générale est simple : utilisez la sous-requête non corrélée par défaut, et la corrélée uniquement quand c’est indispensable.

Sources: MySql, Postgres, SqlServer