web-dev-qa-db-fra.com

Y a-t-il une différence entre un prédicat à l'aide d'une valeur littérale ou d'une valeur de paramètre lorsque cette valeur sera toujours la même?

J'ai une requête qui fait toujours des filtres sur un statut, existe-t-il un avantage de performance de l'une de ces manières de l'autre?

(Ceci est dans le contexte d'une requête ad-hoc. Le type de données d'userstatus est int)

...
AND UserStatus = 1
...

ou alors

DECLARE @userStatus int = 1
...
AND UserStatus = @userStatus
...

(P.S. Veuillez ne pas parler de la manière dont les paramètres et les littéraux sont différents lorsque les valeurs sont inconnues/changent, c'est un sujet différent)

7
JeremyWeir

D'accord en supposant que vous parlez d'une variable locale allant d'une requête dans SSMS, car elle n'a pas été spécifiée autrement. Même si vous utilisez la même valeur pour le AND UserStatus = @userStatus que vous utiliseriez dans le littéral AND UserStatus = 1 Vous verrez une différence dans votre plan d'exécution en raison de la génération de l'estimation de la cardinalité.

Lorsque vous utilisez une valeur littérale, SQL Server s'éteindra à histogramme Pour cette table et voyez où cette valeur de conversation dans la touche de plage. L'estimation recueillie sur cela entraînera l'un des deux scénarios.

Histogramme Direct Hit Cela signifie essentiellement qu'il y a un RANGE_HI_KEY (Valeur supérieure de la colonne pour toute étape de l'histogramme) de la valeur de cette valeur littérale spécifique dans votre requête et que l'estimation correspondra au nombre de EQ_ROWS (nombre de lignes dont la valeur est égale à la RANGE_HI_KEY) dans l'histogramme. Cela signifie que votre estimation sera le nombre de lignes correspondant à cette valeur basée sur la dernière fois que vous avez mis à jour les statistiques.

Histogramme intra-étape Hit Ceci est lorsque la valeur existe dans une plage entre deux RANGE_HI_KEY valeurs. Lorsque votre valeur littérale est entre cette plage, elle est calculée par le RANGE_ROWS (nombre de lignes entre deux étapes d'histogramme), DINSTINCT_RANGE (le nombre de valeurs distinctes dans cette étape d'histogramme) et AVG_RANGE_ROWS (RANGE_ROWS/DISTINCT_RANGE_ROWS) Et cela vous donnera votre estimation.

Toutefois, lorsque vous courez avec une variable locale, vous n'allez plus à l'histogramme pour ces valeurs depuis le @Variable n'est pas connu au moment de l'exécution.

Pour plus d'informations sur ce sujet, je vous recommande de lire ce livre blanc par Joe Sack.

Vecteur de densité Lorsqu'il n'y a pas de valeur spécifique à utiliser avec puis SQL Server utilise plutôt une densité pour pouvoir déterminer le nombre estimé de lignes retournées pour ce prédicat. . Densité Étant 1/Le nombre de valeurs distinctes dans cette colonne. Ainsi, votre estimation de la cardinalité sera de la densité * le nombre de lignes dans la table.

Tellement longue histoire courte no. Même si vous exécutez la même valeur avec une variable locale, vous n'obtiendrez pas les mêmes résultats pour des raisons expliquées davantage dans le lien Eric fourni de Kendra Petit .

11
Zane

Une valeur littérale est connue de l'optimiseur (il peut donc estimer la sélectivité en fonction de cette valeur).

Une valeur de paramètre (procédure stockée, fonction) est renifle au temps d'exécution. Une exécution ultérieure peut avoir une autre valeur, pour laquelle le plan précédemment compilé pourrait ne pas être optimal.

Pour une variable, la valeur n'est pas connue de l'optimiseur. Il pourrait être capable de regarder la densité (sur moyenne Nous avons ces nombreuses lignes pour une certaine valeur) ou utilise des estimations câblées (telles que par exemple, entraînent une sélectivité à 10%, ou quoi que ce soit les pourcentages par câblodités peuvent être).

7
Tibor Karaszi