Différence monumentale dans le temps d'exécution entre les requêtes lors de l'utilisation de l'indicateur de requête RECOMPILE

16

J'ai deux requêtes presque identiques exécutées sur la même instance SQL Server 2005:

  1. La première est la SELECTrequête d' origine générée par LINQ (je sais, je sais ... je ne suis pas le développeur de l'application, juste le DBA :).
  2. Le second est exactement le même que le premier, a ajouté un OPTION (RECOMPILE)à la fin.

Rien d'autre n'a été changé.

Le premier prend 55 secondes à chaque exécution.
Le second prend 2 secondes.

Les deux jeux de résultats sont identiques.

Pourquoi cet indice générerait-il un gain de performances aussi spectaculaire?

L'entrée Books Online sur RECOMPILEn'offre pas une explication très détaillée:

Demande au moteur de base de données SQL Server de supprimer le plan généré pour la requête après son exécution, forçant l'optimiseur de requête à recompiler un plan de requête la prochaine fois que la même requête est exécutée. Sans spécifier RECOMPILE, le moteur de base de données met en cache les plans de requête et les réutilise. Lors de la compilation des plans de requête, l'indicateur de requête RECOMPILE utilise les valeurs actuelles de toutes les variables locales de la requête et, si la requête se trouve dans une procédure stockée, les valeurs actuelles transmises à tous les paramètres.

RECOMPILE est une alternative utile à la création d'une procédure stockée qui utilise la clause WITH RECOMPILE lorsque seul un sous-ensemble de requêtes à l'intérieur de la procédure stockée, au lieu de la procédure stockée entière, doit être recompilé. Pour plus d'informations, consultez Recompilation des procédures stockées. RECOMPILE est également utile lorsque vous créez des repères de plan. Pour plus d'informations, consultez Optimisation des requêtes dans les applications déployées à l'aide des guides de plan.

Étant donné que ma requête contient de nombreuses variables locales, je suppose que SQL Server est en mesure de l'optimiser (sérieusement) lorsque j'utilise l' OPTION (RECOMPILE)indicateur de requête.

Partout où je regarde, les gens disent que cela OPTION (RECOMPILE)devrait être évité. L'explication est généralement que l'utilisation de cet indice SQL Server n'est pas en mesure de réutiliser ce plan d'exection et doit donc perdre du temps à le recompiler à chaque fois.
(Mais) Compte tenu de l'avantage de performance gigantesque, je suis enclin à penser que l'utilisation de cet indice de requête cette fois serait une bonne chose.

Dois-je l'utiliser? Sinon, existe-t-il un moyen de forcer SQL Server à utiliser un meilleur plan d'exécution sans cette indication et sans modifier l'application?

ivanmp
la source

Réponses:

16

Comme indiqué dans l'article Statistiques utilisées par l'Optimiseur de requête dans Microsoft SQL Server 2005

Si vous utilisez une variable locale dans un prédicat de requête au lieu d'un paramètre ou d'un littéral, l'optimiseur recourt à une estimation de qualité réduite ou à une estimation de la sélectivité du prédicat. Utiliser des paramètres ou des littéraux dans la requête au lieu de variables locales

Lorsque l'optimiseur n'a aucune statistique utilisable pour une colonne, il devinera qu'un =prédicat correspondra à 10% des lignes, BETWEEN9% et n'importe lequel >, >=, < and <=correspondra à 30%. Si des statistiques de colonne sont disponibles, un =prédicat sera traité différemment comme ci-dessous.

Même lorsque des variables locales sont utilisées dans une requête, une estimation meilleure qu'une estimation est utilisée dans le cas des prédicats d'égalité. La sélectivité pour les conditions de la forme " @local_variable = column_name" est estimée en utilisant la fréquence de valeur moyenne de l'histogramme pour nom_colonne. Ainsi, par exemple, si la colonne nom_colonne contient toutes les valeurs uniques, une estimation de sélectivité de 1/(number of unique values in column)sera utilisée, ce qui est exact.

C'est donc essentiellement la même chose que l'utilisation de for OPTIMIZE FOR (UNKNOWN). Il peut être plus précis qu'une 10%estimation simple, mais il n'est pas adapté aux valeurs spécifiques que vous interrogez.

Pour forcer SQL Server à optimiser une requête à chaque exécution et à utiliser les valeurs des variables locales pour estimer la cardinalité et le coût lors de l'optimisation de la requête, ajoutez l' RECOMPILEindicateur de requête à la requête.

Avec l'utilisation de RECOMPILEvous, vous obtenez probablement des estimations de cardinalité plus précises et donc un plan différent avec des ordres de jointure / types de jointure plus adaptés au nombre de lignes renvoyées par différentes parties de votre requête réelle.

Martin Smith
la source