J'ai rencontré une situation étrange où l'ajout OPTION (RECOMPILE)
à ma requête entraîne son exécution en une demi-seconde, tandis que son omission entraîne la durée de la requête bien plus de cinq minutes.
C'est le cas lorsque la requête est exécutée depuis l'Analyseur de requêtes ou depuis mon programme C # via SqlCommand.ExecuteReader()
. Appeler (ou ne pas appeler) DBCC FREEPROCCACHE
ou DBCC dropcleanbuffers
ne fait aucune différence; Les résultats de la requête sont toujours renvoyés instantanément avec OPTION (RECOMPILE)
et plus de cinq minutes sans. La requête est toujours appelée avec les mêmes paramètres [pour le bien de ce test].
J'utilise SQL Server 2008.
Je suis assez à l'aise avec l'écriture de SQL, mais je n'ai jamais utilisé de OPTION
commande dans une requête auparavant et je ne connaissais pas tout le concept des caches de plan avant de scanner les messages sur ce forum. D'après ce que je comprends des messages, c'est OPTION (RECOMPILE)
une opération coûteuse. Cela crée apparemment une nouvelle stratégie de recherche pour la requête. Alors pourquoi est-ce que les requêtes suivantes qui omettent le OPTION (RECOMPILE)
sont si lentes? Les requêtes suivantes ne devraient-elles pas utiliser la stratégie de recherche qui a été calculée lors de l'appel précédent qui incluait l'indication de recompilation?
Est-il très inhabituel d'avoir une requête qui nécessite un indice de recompilation à chaque appel?
Désolé pour la question d'entrée de gamme, mais je ne peux pas vraiment en faire la tête ou la queue.
MISE À JOUR: on m'a demandé de publier la requête ...
select acctNo,min(date) earliestDate
from(
select acctNo,tradeDate as date
from datafeed_trans
where feedid=@feedID and feedDate=@feedDate
union
select acctNo,feedDate as date
from datafeed_money
where feedid=@feedID and feedDate=@feedDate
union
select acctNo,feedDate as date
from datafeed_jnl
where feedid=@feedID and feedDate=@feedDate
)t1
group by t1.acctNo
OPTION(RECOMPILE)
Lors de l'exécution du test à partir de l'Analyseur de requêtes, j'ajoute les lignes suivantes:
declare @feedID int
select @feedID=20
declare @feedDate datetime
select @feedDate='1/2/2009'
Lors de son appel depuis mon programme C #, les paramètres sont transmis via la SqlCommand.Parameters
propriété.
Pour les besoins de cette discussion, vous pouvez supposer que les paramètres ne changent jamais afin que nous puissions exclure un paramètre sous-optimal sentant comme la cause.
la source
X = @X OR @X IS NULL
àX=@X
et effectuer une cherchent Voir ici ou en poussant prédicats plus bas contre une vue avec des fonctions de fenêtreRECOMPILE
. Dans tous les cas, saisissez les plans d'exécution et examinez les différences.Réponses:
Il y a des moments où l'utilisation a du
OPTION(RECOMPILE)
sens. D'après mon expérience, le seul moment où c'est une option viable est lorsque vous utilisez SQL dynamique. Avant d'explorer si cela a du sens dans votre situation, je vous recommande de reconstruire vos statistiques. Cela peut être fait en exécutant ce qui suit:Et puis recréer votre plan d'exécution. Cela garantira que lorsque votre plan d'exécution sera créé, il utilisera les dernières informations.
L'ajout
OPTION(RECOMPILE)
reconstruit le plan d'exécution chaque fois que votre requête s'exécute. Je n'ai jamais entendu cela décrit comme,creates a new lookup strategy
mais peut-être que nous utilisons simplement des termes différents pour la même chose.Lorsqu'une procédure stockée est créée (je soupçonne que vous appelez ad-hoc sql à partir de .NET, mais si vous utilisez une requête paramétrée, cela finit par être un appel proc stocké ) SQL Server tente de déterminer le plan d'exécution le plus efficace pour cette requête en fonction des données de votre base de données et des paramètres transmis ( détection des paramètres ), puis met en cache ce plan. Cela signifie que si vous créez la requête dans laquelle il y a 10 enregistrements dans votre base de données, puis que vous l'exécutez lorsqu'il y a 100 000 000 d'enregistrements, le plan d'exécution mis en cache peut ne plus être le plus efficace.
En résumé - je ne vois aucune raison pour laquelle ce
OPTION(RECOMPILE)
serait un avantage ici. Je pense que vous avez juste besoin de mettre à jour vos statistiques et votre plan d'exécution. La reconstruction des statistiques peut être une partie essentielle du travail de DBA en fonction de votre situation. Si vous rencontrez toujours des problèmes après la mise à jour de vos statistiques, je vous suggère de publier les deux plans d'exécution.Et pour répondre à votre question - oui, je dirais qu'il est très inhabituel que votre meilleure option soit de recompiler le plan d'exécution chaque fois que vous exécutez la requête.
la source
OPTION (RECOMPILE)
pourrait être la seule solution.Souvent, lorsqu'il y a une différence drastique d'une exécution à l'autre d'une requête, je trouve que c'est souvent l'un des 5 problèmes.
STATISTIQUES- Les statistiques sont obsolètes. Une base de données stocke des statistiques sur la plage et la distribution des types de valeurs dans diverses colonnes des tables et des index. Cela aide le moteur de requête à développer un «plan» d'attaque sur la façon dont il va effectuer la requête, par exemple le type de méthode qu'il utilisera pour faire correspondre les clés entre les tables en utilisant un hachage ou en parcourant l'ensemble complet. Vous pouvez appeler Update Statistics sur l'ensemble de la base de données ou uniquement sur certaines tables ou index. Cela ralentit la requête d'une exécution à une autre car lorsque les statistiques sont obsolètes, il est probable que le plan de requête ne soit pas optimal pour les données nouvellement insérées ou modifiées pour la même requête (expliqué plus loin ci-dessous). Il peut ne pas être approprié de mettre à jour les statistiques immédiatement sur une base de données de production car il y aura une surcharge, un ralentissement et un décalage en fonction de la quantité de données à échantillonner. Vous pouvez également choisir d'utiliser une analyse complète ou un échantillonnage pour mettre à jour les statistiques. Si vous regardez le plan de requête, vous pouvez également afficher les statistiques sur les index en cours d'utilisation en utilisant la commandeDBCC SHOW_STATISTICS (nom de table, nom d'index) . Cela vous montrera la distribution et les plages des clés sur lesquelles le plan de requête utilise pour baser son approche.
PARAMETER SNIFFING - Le plan de requête mis en cache n'est pas optimal pour les paramètres particuliers que vous transmettez, même si la requête elle-même n'a pas changé. Par exemple, si vous transmettez un paramètre qui ne récupère que 10 sur 1000000 lignes, le plan de requête créé peut utiliser une jointure par hachage, mais si le paramètre que vous transmettez utilise 750000 des 1000000 lignes, le plan créé peut être un analyse d'index ou analyse de table. Dans une telle situation, vous pouvez indiquer à l'instruction SQL d'utiliser l'option OPTION (RECOMPILE) ou un SP à utiliser WITH RECOMPILE. Dire au moteur qu'il s'agit d'un "plan à usage unique" et ne pas utiliser un plan mis en cache qui ne s'applique probablement pas. Il n'y a pas de règle sur la façon de prendre cette décision, cela dépend de la connaissance de la manière dont la requête sera utilisée par les utilisateurs.
INDEXES - Il est possible que la requête n'ait pas changé, mais un changement ailleurs tel que la suppression d'un index très utile a ralenti la requête.
ROWS CHANGED - Les lignes que vous interrogez changent radicalement d'un appel à l'autre. Les statistiques sont généralement mises à jour automatiquement dans ces cas. Cependant, si vous créez du SQL dynamique ou que vous appelez du SQL dans une boucle serrée, il est possible que vous utilisiez un plan de requête obsolète basé sur le mauvais nombre drastique de lignes ou de statistiques. Encore une fois dans ce cas OPTION (RECOMPILE) est utile.
LA LOGIQUE C'est la logique, votre requête n'est plus efficace, c'était bien pour un petit nombre de lignes, mais plus d'échelle. Cela implique généralement une analyse plus approfondie du plan de requête. Par exemple, vous ne pouvez plus faire les choses en vrac, mais vous devez fragmenter les choses et faire des Commits plus petits, ou votre produit croisé était bien pour un ensemble plus petit mais prend maintenant du processeur et de la mémoire à mesure qu'il évolue plus grand, cela peut aussi être vrai pour en utilisant DISTINCT, vous appelez une fonction pour chaque ligne, vos correspondances clés n'utilisent pas d'index à cause de la conversion de type CASTING ou de NULLS ou de fonctions ... Trop de possibilités ici.
En général, lorsque vous écrivez une requête, vous devez avoir une idée de la façon dont certaines données sont distribuées dans votre table. Une colonne, par exemple, peut avoir un nombre uniformément réparti de valeurs différentes, ou elle peut être biaisée, 80% du temps avoir un ensemble spécifique de valeurs, que la distribution varie fréquemment dans le temps ou soit assez statique. Cela vous donnera une meilleure idée de la façon de créer une requête efficace. Mais aussi lors du débogage, les performances des requêtes ont une base pour construire une hypothèse expliquant pourquoi elles sont lentes ou inefficaces.
la source
Pour ajouter à l'excellente liste (donnée par @CodeCowboyOrg) des situations où OPTION (RECOMPILE) peut être très utile,
la source
La toute première action avant de régler les requêtes consiste à défragmenter / reconstruire les index et les statistiques, sinon vous perdez votre temps.
Vous devez vérifier le plan d'exécution pour voir s'il est stable (c'est le même lorsque vous modifiez les paramètres), sinon, vous devrez peut-être créer un index de couverture (dans ce cas pour chaque table) (connaissant le système, vous pouvez en créer un qui est également utile pour d'autres requêtes).
comme exemple: créer l'index idx01_datafeed_trans On datafeed_trans (feedid, feedDate) INCLUDE (acctNo, tradeDate)
si le plan est stable ou si vous pouvez le stabiliser, vous pouvez exécuter la phrase avec sp_executesql ('phrase sql') pour enregistrer et utiliser un plan d'exécution fixe.
si le plan est instable, vous devez utiliser une instruction ad hoc ou EXEC ('phrase sql') pour évaluer et créer un plan d'exécution à chaque fois. (ou une procédure stockée "avec recompilation").
J'espère que ça aide.
la source
Necroing cette question mais il y a une explication que personne ne semble avoir envisagée.
STATISTIQUES - Les statistiques ne sont pas disponibles ou trompeuses
Si toutes les conditions suivantes sont vraies:
Ensuite, le serveur SQL peut supposer à tort que les colonnes ne sont pas corrélées, ce qui entraîne des estimations de cardinalité inférieures aux prévisions pour l'application des deux restrictions et la sélection d'un plan d'exécution médiocre. Le correctif dans ce cas serait de créer un objet de statistiques reliant les deux colonnes, ce qui n'est pas une opération coûteuse.
la source