N'EXISTE PAS vs PAS DANS
Je suis l'optimisation de certaines requêtes SQL (ce qui pourrait être considéré comme la partie 2 de une question que j'ai posté) et le remplacement de quelques PAS avec n'EXISTE PAS de prédicats
Suis-je en droit de penser que le principal avantage de cela est qu'avec n'EXISTE PAS vous obtenir l'avantage que l'état va s'arrêter lorsqu'une seule correspondance est trouvée, mais PAS avec un comptage de sous-requête serait serait de faire un full table scan?
Il semble également que N'EN aurait aussi besoin de plus de travail si les données sélectionnées contenues Null, est-ce correct?
J'ai besoin de faire en sorte que la deuxième déclaration de mieux que le premier (et fonctionnellement équivalent) dans ces deux cas, avant que je les mettre en œuvre dans le proc:
Cas 1:
--exclude sessions that were tracked as part of a conversion during the last response_time minutes
-- AND session_id NOT IN (SELECT DISTINCT tracked_session_id
-- FROM data.conversions WITH (NOLOCK)
-- WHERE client_id = @client_id
-- AND utc_date_completed >= DATEADD(minute, (-2) * cy.response_time, @date)
-- AND utc_date_completed <= @date
-- AND utc_date_clicked <= @date)
AND NOT EXISTS (SELECT 1
FROM data.conversions WITH (NOLOCK)
WHERE client_id = @client_id
AND utc_date_completed >= DATEADD(minute, (-2) * cy.response_time, @date)
AND utc_date_completed <= @date
AND utc_date_clicked <= @date
AND data.conversions.tracked_session_id = d.session_id
)
Cas 2:
-- NOT EXISTS vs full table scan with COUNT(dashboard_id)
-- AND (SELECT COUNT(dashboard_id)
-- FROM data.dashboard_responses WITH(NOLOCK)
-- WHERE session_id = d.session_id
-- AND cycle_id = cy.id
-- AND client_id = @client_id) = 0
AND NOT EXISTS(SELECT 1
FROM data.dashboard_responses
WHERE session_id = d.session_id
AND cycle_id = cy.id
AND client_id = @client_id)
Acclamations
- Le plan d'exécution de ne pas vous dire si ce N'exécute une analyse de la table? Personnellement, je ne regarde que le plan dit concernant les performances des entrées/sorties statistiques sur quoi que ce soit d'autre.
- double possible de What est la différence entre n'EXISTE PAS contre PAS contre une JOINTURE GAUCHE OÙ EST NULL?
- Malheureusement je ne peux pas (facilement) de l'exécution de ces procédures stockées dans la source de données pour obtenir un plan de requête
- À partir d'Oracle 10g AU/PAS explicitement converti EXISTE/N'. Le PAS est aussi efficace que n'EXISTE PAS. Mais n'utilisez PAS DANS votre sous-requête peut retourner NULL.
- double possible de PAS DE vs n'EXISTE PAS
Vous devez vous connecter pour publier un commentaire.
Comme vous l'avez justement dit que les deux sont des choses différentes. Si la sous-requête des éléments à ne pas être
IN
contientNULL
pas de résultats retournés parce que rien n'égaleNULL
et rien n'égale pasNULL
(même Pas NULL).En supposant que vous utilisez les deux pour obtenir le même résultat, il n'y a pas de différence entre les deux, tant que vous manipulez
NULL
valeurs dans votreIN
déclaration. L'optimiseur est assez intelligent pour savoir qu'avecNULL
valeurs éliminé, ou avec des non nullable colonnes les deux sont les mêmes, donc utiliser le mêmeANTI SEMI JOIN
.Tenir compte de ces deux tableaux:
Ces deux requêtes obtenir exactement le même plan d'exécution:
parce que l'optimiseur sait T2.ID est un non nullable colonne. Avec une troisième table:
où la colonne ID est ni indexé ou nullable ces deux requêtes rendu très différents plans d'exécution:
et n'EXISTE PAS en sera d'autant plus efficace. Cependant, ces deux de nouveau de rendement (pour l'essentiel) le même plan d'exécution:
Toutes ces requêtes et des données de l'échantillon sont sur SQL Violon
MODIFIER
À fait répondre à votre question:
Cas 1 seront les mêmes performances avec
NOT IN
ouNOT EXISTS
sitracked_session_id
est un non nullable colonne dansdata.conversions
, ou vous ajouterWHERE tracked_Session_id IS NOT NULL
Dans la déclaration. Si la colonne n'est pas les valeurs null et que vous n'excluez pas les valeurs null de la performance ne sera pas le même, et en supposant qu'il n'existe pas de valeurs nullNOT EXISTS
fonctionnera mieux, si il n'existe pas de valeurs null, le résultat ne sera pas le même si les performances ne sont pas comparables.Cas 2 fait de me surprendre avec un échantillon de données, j'avais supposé que ce ne serait pas optimisé dans un
ANTI SEMI JOIN
, et avait déjà écrit une réponse en dit autant, mais juste avant d'enregistrer le modifier j'ai pensé que je ferais mieux de vérifier, et a été surpris de voir que ce n':Est optimisé exactement le même que
NOT EXISTS
. Donc, il semble que l'optimiseur est même plus intelligent que je ne le pensais, il ne fera que générer un plan différent, si vous voulez le comte à être autre chose que 0.SQL Violon pour le Cas 2
count(*) = 0
etcount(*) > 0
en raison de beaucoup de personnes utilisant cette syntaxe pour des instructions if. Si existe, c'est le meilleur choix en raison d'être techniquement correct. blogs.technet.com/b/wardpond/archive/2007/08/27/...Vous avez raison qu'il y est une grande différence avec les valeurs null. Un
NOT IN
requête vérifie que chaque élément définitivement ne correspond pas. Une comparaison avec la valeur null n'est pas de produire un résultat définitif. Ainsi, si votre sous-requête contient une valeur null, rien ne sera considéré comme "NOT IN
" il.Voir ce SQL Violon exemple.
La non-intuitif effet secondaire de ce comportement est que
NOT IN
n'est pas en fait le contraire deIN
.Un
NOT EXISTS
requête n'a pas ce problème.J'hésite à faire toute déclaration générale sur ce qui fonctionne mieux, car cela dépend souvent de ce genre d'optimisations se produire. C'est pourquoi être en mesure de trouver le plan d'exécution est important si vous vous souciez de la performance.
NOT EXISTS
exécute une requête, compte le nombre de lignes, et si le count==0, puis retournetrue
.NOT IN
exécute une requête, itère sur le résultat, compare la valeur donnée pour le résultat, et si aucune correspondance n'est trouvée, il retournetrue
Généralement la première méthode est beaucoup plus rapide.
Bien sûr, vous avez à prendre soin, à ce que les colonnes/valeurs-vous d'inclure dans votre sous-requête à partir de l'environnement de requêtes, car il peut en résulter que votre sous-requête s'exécute N fois (une fois pour chaque ligne de l'externe resultset).
Il y a une autre approche: table de jointure avec une
OUTER JOIN
à la table B, et de vérifier si la colonne dans la table B estNULL
. Cela permettra de exécuter votre requête qu'une seule fois. C'van être utilisé dans les cas les plus simples uniquement (ne fonctionne pas pour plusieurs jointure de table chaînes).NOT EXISTS
peut résilier dès que son trouvé un seul match, de même,NOT IN
peut être optimisée pour effectuer uneLEFT ANTI SEMI JOIN
qui également s'arrête lorsqu'il trouve son premier match, et peuvent utiliser les index.NOT EXISTS
etNOT IN
sont à la fois optimisé pour l'utilisation d'unLEFT ANTI SEMI JOIN
.