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.
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.
En guise de solution temporaire, je l’ai modifiée pour qu’elle compte (*) et affecte cette valeur à une variable.
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'autre SELECT TOP (1)
formulation que vous avez essayé. Cela peut être mieux que d’utiliser COUNT(*)
, 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:
DECLARE @Exists bit;
SELECT @Exists =
CASE
WHEN 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]
)
THEN CONVERT(bit, 1)
ELSE CONVERT(bit, 0)
END
OPTION (QUERYTRACEON 4138);
IF @Exists = 1
BEGIN
...
END;
IF NOT EXISTS (...) BEGIN END ELSE BEGIN <do something> END
.