
IN et EXISTS servent tous deux à tester l’appartenance dans une sous-requête, mais EXISTS s’arrête dès la première correspondance trouvée, tandis que IN évalue toute la liste. Lequel est le plus rapide ? Ça dépend des données — voici la règle pratique et les exemples Oracle.
Syntaxe : deux façons d’écrire la même intention
-- clients ayant au moins une commande
-- avec IN
SELECT * FROM clients c
WHERE c.id IN (SELECT client_id FROM commandes);
-- avec EXISTS
SELECT * FROM clients c
WHERE EXISTS (SELECT 1 FROM commandes cmd WHERE cmd.client_id = c.id);La différence de fonctionnement
- IN : construit l’ensemble des valeurs de la sous-requête, puis vérifie l’appartenance.
- EXISTS : pour chaque ligne externe, teste s’il existe au moins une ligne correspondante, et s’arrête au premier match (corrélé).
Quel est le plus rapide ?
Avec les optimiseurs Oracle modernes, les deux donnent souvent le même plan d’exécution. La règle empirique reste utile :
- EXISTS est avantageux quand la sous-requête est grande et qu’on cherche juste « existe-t-il… ? » (il s’arrête tôt).
- IN est pratique quand la sous-requête renvoie une petite liste de valeurs.
Dans le doute, comparez avec EXPLAIN PLAN — c’est le seul juge fiable.
Le piège majeur : NOT IN et les NULL
C’est LA raison de préférer souvent NOT EXISTS : si la sous-requête de NOT IN contient une seule valeur NULL, le résultat devient… vide (aucune ligne) !
-- ❌ DANGER : si commandes.client_id contient un NULL, 0 ligne renvoyée
SELECT * FROM clients
WHERE id NOT IN (SELECT client_id FROM commandes);
-- ✅ robuste face aux NULL
SELECT * FROM clients c
WHERE NOT EXISTS (SELECT 1 FROM commandes cmd WHERE cmd.client_id = c.id);Pour les clients sans commande, préférez donc NOT EXISTS (ou un LEFT JOIN … IS NULL).
Et la jointure dans tout ça ?
Souvent, un simple JOIN exprime la même chose plus clairement et aussi efficacement :
SELECT DISTINCT c.*
FROM clients c JOIN commandes cmd ON cmd.client_id = c.id;(Attention au DISTINCT qui peut coûter cher : EXISTS l’évite naturellement.)
Récapitulatif
- « Au moins une correspondance » sur grosse sous-requête → EXISTS.
- Petite liste de valeurs fixes → IN.
- « Ceux qui n’ont pas… » → NOT EXISTS (jamais NOT IN avec des NULL possibles).
FAQ
IN ou EXISTS : la performance change-t-elle vraiment ?
Sur Oracle récent, souvent non (même plan). La différence se voit surtout sur de très gros volumes ou des sous-requêtes corrélées — mesurez avec EXPLAIN PLAN.
Pourquoi NOT IN renvoie 0 ligne parfois ?
Parce que la sous-requête contient une valeur NULL : en logique SQL, « x NOT IN (…, NULL) » devient indéterminé. Utilisez NOT EXISTS.
EXISTS avec SELECT 1 ou SELECT * ?
Aucune différence de performance : Oracle ne lit pas les colonnes dans un EXISTS. SELECT 1 est juste une convention de lisibilité.
