J'ai entendu dire que NOT IN devrait être évité à tout prix, donc je mets à jour mes requêtes pour utiliser NOT EXISTS et exécuter EXPLAIN ANALYZE sur eux pour voir s'il y a des améliorations, mais j'ai du mal à comprendre. Comment puis-je convertir une requête comme celle-ci:
SELECT id
FROM customers c
WHERE c.status NOT IN
('DELETED', 'ARCHIVED', 'EXPIRED'')
3 Réponses :
Cela peut être vrai si vous utilisez not in avec une sélection imbriquée, par exemple:
select id
from customer c
where not exists(
select *
from status s
where (s.id, s.type) = (c.status_id, 'DELETED')
)
Cela devrait plutôt être réécrit en:
select id
from customer c
where c.status_id not in (
select id
from status s
where s.type = 'DELETED'
)
Mais puisque vous utilisez not in avec un ensemble de valeurs possibles, c'est ok et il serait même difficile de le réécrire en utilisant existe .
J'admets que je n'ai jamais vu la syntaxe where (s.id, s.type) = (c.status_id, 'DELETED') auparavant - est-ce unique à Postgres?
@Dai c'est un peu plus compact. C'est la même chose que s.id = c.status_id et s.type = 'DELETED'
@Dai oui, c'est un truc de postgres. Vous pouvez voter si vous avez appris quelque chose d'utile;>
J'ai entendu dire que
NOT INdevrait être évité à tout prix.Vous avez mal entendu - et vous appliquez quelque chose que vous ne comprenez pas (ou quelque chose que vous acceptez pour argent comptant sans aucune enquête de votre part) en production. Ce que vous professez est un exemple de Programmation Cargo-Cult . Ne fais pas ça. Ne croyez rien de ce que vous lisez sans citations et sources (cela s'applique à tout dans la vie, btw)
Quoi qu'il en soit,
NOT INetNOT EXISTSsont pas sémantiquement équivalent:IN(etNOT IN) lorsqu'il est utilisé avec des valeurs littérales variadiques ou des paramètres variadiques est juste du sucre syntaxique pour une instructionORrépétée , alors queNOT EXISTSest un test d'appartenance à l'ensemble, ce qui est une opération très différente.Dans votre cas, ceci:
WHERE NOT ( c.status = 'DELETED' OR c.status = 'ARCHIVED' OR c.status = 'EXPIRED' )
Vous avez entendu la règle de manière incomplète. C'est faux:
J'ai entendu dire que NOT IN devrait être évité à tout prix,. . .
C'est beaucoup plus proche d'être vrai:
J'ai entendu dire que NOT IN avec une sous-requête devrait être évité à tout prix,. . .
Il y a deux raisons à cela. Le plus important est de loin la gestion des valeurs NULL . Si une valeur renvoyée par la sous-requête est NULL , alors NOT IN jamais renvoie TRUE code >. Autrement dit, la requête ne renvoie aucune ligne (si c'est la seule condition).
D'un autre côté, NOT EXISTS fait ce que vous attendez dans ce cas, en ignorant essentiellement les valeurs NULL dans la sous-requête.
Ce n'est pas un problème avec les listes explicites, car il est peu probable que vous incluiez une valeur NULL dans une liste explicite.
Le deuxième problème concerne les performances. Certaines bases de données optimiseront NOT EXISTS avec une sous-requête bien meilleure que NOT IN - en particulier si les index appropriés sont disponibles.
"J'ai entendu dire que
NOT INdevrait être évité à tout prix" - où avez-vous entendu cela? Je ne suis pas d'accord avec cette affirmation. N'oubliez pas que toutes les généralisations sont fausses, y compris celle-ci!«À tout prix» était probablement une affirmation exagérée, j'aurais dû le formuler plus soigneusement. Il s'agissait plutôt d'un conseil de type "soyez prudent lorsque vous utilisez
pas dans"En fait, pour votre requête mentionnée dans la question NOT IN est assez bonne. la clause exist est meilleure lorsque vous utilisez une sous-requête dans la clause where pour vérifier l'existence d'une valeur
@AkhileshMishra la requête réelle est un peu plus encombrée dans les déclarations
dansetpas dansmais je ne voulais pas publier l'original sans tout masquer, j'ai donc publié une version simplifiéeJe n'ai aucune connaissance de l'optimisation postgres mais IME avec d'autres produits, les problèmes avec
NOT INsont généralement associés àNOT IN (sub_query)surtout si la sub_query peut renvoyer < code> NULL .Une réponse de ligne pour toutes vos requêtes est
NOT INest bonne lorsque vous avez un ensemble de valeurs statiques (comme en question) Mais NOT EXIST est toujours bonne lorsque vous voulez le vérifier via une sous-requête.@AkhileshMishra C'est parfaitement logique, merci