Lorsque je lance le code suivant, cela prend 22,5 minutes et 106 millions de lectures. Cependant, si je lance uniquement l'instruction select interne en elle-même, cela ne prend que 15 secondes et 264k lectures. En remarque, la requête sélectionnée ne renvoie aucun enregistrement.
Avez-vous une idée de la raison pour laquelle le programme IF EXISTS
durerait beaucoup plus longtemps et ferait beaucoup plus de lectures? J'ai également changé l'instruction select à faire SELECT TOP 1 [dlc].[id]
et je l'ai tuée après 2 minutes.
En guise de solution temporaire, je l’ai modifiée pour qu’elle compte (*) et affecte cette valeur à une variable @cnt
. Ensuite, il fait une IF 0 <> @cnt
déclaration. Mais je pensais que ce EXISTS
serait mieux, car si des enregistrements étaient renvoyés dans l'instruction select, ils ne procéderaient plus à l'analyse / à la recherche une fois qu'ils auraient trouvé au moins un enregistrement, alors que la count(*)
requête complète serait complétée. Qu'est-ce que je rate?
IF EXISTS
(SELECT [dlc].[ID]
FROM TableDLC [dlc]
JOIN TableD [d]
ON [d].[ID] = [dlc].[ID]
JOIN TableC [c]
ON [c].[ID] = [d].[ID2]
WHERE [c].[Name] <> [dlc].[Name])
BEGIN
<do something>
END
la source
IF NOT EXISTS (...) BEGIN END ELSE BEGIN <do something> END
.Réponses:
Comme je l'ai expliqué dans ma réponse à cette question connexe:
Comment (et pourquoi) TOP impacte-t-il un plan d'exécution?
L'utilisation
EXISTS
introduit un objectif de ligne, dans lequel l'optimiseur génère un plan d'exécution visant à localiser rapidement la première ligne. Ce faisant, il suppose que les données sont uniformément distribuées. Par exemple, si les statistiques indiquent qu'il y a 100 correspondances attendues sur 100 000 lignes, cela suppose qu'il ne faudra lire que 1 000 lignes pour trouver la première correspondance.Cela se traduira par des temps d'exécution plus longs que prévu si cette hypothèse s'avère erronée. Par exemple, si SQL Server choisit une méthode d'accès (par exemple, une analyse non ordonnée) permettant de localiser la première valeur correspondante très tard dans la recherche, une analyse presque complète pourrait en résulter. D'autre part, si une ligne correspondante se trouve parmi les premières lignes, les performances seront très bonnes. C'est le risque fondamental avec les objectifs de rangée - une performance incohérente.
Il est généralement possible de reformuler la requête de manière à ce qu'aucun objectif de ligne ne soit attribué. Sans l'objectif de ligne, la requête peut toujours se terminer lorsque la première ligne correspondante est rencontrée (si elle est écrite correctement), mais la stratégie de plan d'exécution risque d'être différente (et, espérons-le, plus efficace). De toute évidence, compter (*) nécessitera la lecture de toutes les lignes. Ce n'est donc pas une alternative parfaite.
Si vous exécutez SQL Server 2008 R2 ou une version ultérieure, vous pouvez également utiliser généralement l' indicateur de suivi documenté et pris en charge 4138 pour obtenir un plan d'exécution sans objectif de ligne. Cet indicateur peut également être spécifié à l'aide de l' indicateur pris en charge. Sachez
OPTION (QUERYTRACEON 4138)
toutefois qu'il nécessite une autorisation sysadmin d' exécution , à moins qu'il ne soit utilisé avec un repère de plan.Malheureusement
Aucune de ces réponses n'est fonctionnelle avec une
IF EXISTS
instruction conditionnelle. Cela s'applique uniquement aux DML ordinaires. Il va travailler avec l'autreSELECT TOP (1)
formulation que vous avez essayé. Cela peut être mieux que d’utiliserCOUNT(*)
, qui doit compter toutes les lignes qualifiées, comme mentionné précédemment.Cela dit, il existe un certain nombre de façons d’exprimer cette exigence qui vous permettront d’éviter ou de contrôler l’objectif de la ligne, tout en mettant fin à la recherche plus tôt. Un dernier exemple:
la source
Comme EXISTS n'a besoin que de trouver une seule ligne, il utilisera un objectif de ligne. Cela peut parfois produire un plan moins qu'idéal. Si vous vous attendez à ce que ce soit le cas, renseignez une variable avec le résultat de a
COUNT(*)
, puis testez-la pour voir si elle est supérieure à 0.Alors ... Avec un objectif de petite ligne, cela évitera les opérations de blocage, telles que la construction de tables de hachage, ou le tri des flux qui pourraient être utiles pour la fusion des jointures, car il est évident que la recherche de quelque chose est voué à être rapide, et que, par conséquent, les boucles imbriquées être le meilleur si il a trouvé quelque chose. Sauf que cela peut rendre un plan qui est bien pire dans l'ensemble. Si trouver une seule ligne a été rapide, vous aimeriez cette méthode pour éviter les blocs ...
la source