TSQL: rechercher des requêtes provoquant trop de compilations SQL et de recompilations SQL séparément

8

Je veux savoir ce qui cause les hautes compilations SQL (pas les recompilations) que je vois dans les compteurs de moniteur de performances.

Voici mon point de vue: si je vois beaucoup de compilations SQl, cela signifie que les requêtes sur notre système ne sont pas mises en cache pour les raisons suivantes:

  • De nombreuses requêtes ad hoc
  • Exécution de requêtes que SQl ne met pas en cache, par exemple:

    UPDATE table1 SET col1 = 'Chaîne de plus de 8000 caractères .....' OERE key_column = certains int

  • Les plans expirent et sont supprimés du cache car: Le cache manque d'espace ou les plans ne sont pas utilisés assez longtemps.

La seule chose qui se rapproche de la capture d'insertions de cache dans le profileur est les procédures stockées-> SP: CacheInserts, mais il ne s'occupe que du cache des procédures stockées.

J'ai donc essayé ce qui suit pour obtenir des requêtes ad hoc:

SELECT [cp].[refcounts] -- when Refcounts becomes 0, plan is excluded from cache.
    , [cp].[usecounts] 
    , [cp].[objtype] 
    , st.[dbid] 
    , st.[objectid] 
    , st.[text] 
    , [qp].[query_plan] 
FROM sys.dm_exec_cached_plans cp     
CROSS APPLY sys.dm_exec_sql_text ( cp.plan_handle ) st     
CROSS APPLY sys.dm_exec_query_plan ( cp.plan_handle ) qp ;

Je pensais que les requêtes à l'origine des compilations devraient être celles avec objtype = Adhoc mais cela pourrait également concerner les recompilations. Maintenant, je dois exécuter le profileur, capturer les requêtes provoquant des recompilations, puis l'exclure de la liste ci-dessus.

Suis-je dans la bonne direction?

Existe-t-il une seule requête que je peux utiliser pour réaliser uniquement des compilations SQL sans trop de travail?

Ressources qui m'ont aidé à acquérir les connaissances ci-dessus:

http://social.msdn.microsoft.com/Forums/en/sqldatabaseengine/thread/954b4fba-3774-42e3-86e7-e5172abe0c83 http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=143946 http: //technet.microsoft.com/en-nz/library/cc966425(en-us).aspx
http://www.sqlservercentral.com/Forums/Topic914951-360-1.aspx

Toute aide est vraiment appréciée.

Manjot
la source

Réponses:

7

Je ne pense pas que vous puissiez trouver cela facilement, mais il est de toute façon possible de passer au travers. Le profileur propose de nombreux types de classes d'événements qui peuvent être utilisés pour analyser les performances d'une requête. Démarrez une nouvelle session Profiler et vérifiez les événements suivants:

Performance: Performance statistics
Stored Procedures: RPC:Completed
TSQL: SQL:BatchCompleted
TSQL: SQL: BatchStarting

Cochez la case Afficher toutes les colonnes et sélectionnez chacune des colonnes sous Performances: événement Statistiques de performances uniquement. Le reste des événements peut être laissé avec le réglage par défaut.

Ensuite, sélectionnez Filtres de colonne et filtrez par DatabaseName et / ou LoginName / ApplicationName / HostName etc., si vous les connaissez. Le but est de limiter le nombre de lignes affichées dans Profiler et de se concentrer uniquement sur vos besoins.

Ensuite, appuyez sur Exécuter et laissez-le fonctionner pendant un certain temps (2-3 minutes aussi longtemps que vous en avez besoin). Analyser les résultats affichés en regardant principalement: Événement de statistiques de performance.

Si les statistiques de performances se produisent souvent, cela signifie que le plan d'une requête a été mis en cache pour la première fois, compilé, recompilé ou expulsé de PlanCache. D'après mes connaissances, si une requête n'a pas son plan de requête dans Plan Cache - vous verrez 2 lignes d' événement PerformanceStatistics et suivies de SQL: BatchStarting , puis SQL: BatchCompleted . Cela signifie que le plan de requête a d'abord été compilé, mis en cache, puis la requête a commencé et s'est terminée.

Regardez les colonnes suivantes sous l'événement Statistiques de performances:

SPID - ID of the session on which the event occurred. You can use it to identify the       
       row on SQL:BatchCompleted event which will display the SQL Query text and other  
       usefull information (Read/Writes, StartTime/EndTime)
Duration - Total time, in microseconds, spent during compilation.
EventSubClass - 0 = New batch SQL text that is not currently present in the cache.
                1 = Queries within a stored procedure have been compiled.
                2 = Queries within an ad hoc SQL statement have been compiled.
                3 = A cached query has been destroyed and the historical performance         
                    data associated with the plan is about to be destroyed.
                4 = A cached stored procedure has been removed from the cache and the  
                    historical performance data associated with it is about to be 
                    destroyed.

                5 = A cached trigger has been removed from the cache and the historical  
                    performance data associated with it is about to be destroyed.

Compte tenu du numéro EventSubClass, vous pouvez découvrir ce qui s'est passé avec le plan de requête et prendre des mesures spécifiques. En outre, vous pouvez ajouter d'autres colonnes aux procédures stockées et aux classes d'événements TSQL si vous êtes intersecté dans HostName, WindowsUser ou d'autres informations de la trace du Générateur de profils. La trace peut également être stockée dans une table SQL, ce qui rend l'analyse plus facile et beaucoup plus personnalisable. Voici un lien décrivant davantage la classe d'événements Performance Statistics.

yrushka
la source
4

Eh bien, voyons d'abord s'il y a de la pression sur le cache.

select bpool_visible from sys.dm_os_sys_info
go

Multipliez ce nombre par 8 pour obtenir la mémoire en K. 75% de ceci de 0-4G + 10% de ceci de 4G-64G + 5% de plus est la limite de pression de cache du plan . Si vous atteignez 75% de cette limite, SQL Server commencera à purger les plans du cache. Cette purge se produit lorsqu'un nouveau plan de requête est ajouté au cache, de sorte que le thread s'arrête pour effectuer ce travail. La deuxième chose qui peut entraîner la purge des plans est si le nombre de plans dépasse 4x le nombre de compartiments de hachage (une table de hachage mappe un plan_handle à un plan). Il y en a 10 000 sur un système 32 bits et 40 000 sur un système 64 bits.

select type, sum(pages_allocated_count) as pages_used from sys.dm_os_memory_objects 
where type in ('MEMOBJ_CACHESTOREOBJCP', 'MEMOBJ_CACHESTORESQLCP', 'MEMOBJ_CACHESTOREXPROC')
group by type
go

La décision sur ce qu'il faut purger n'est pas prise en fonction de l'utilisation, mais du coût du plan, les plans les moins chers sont purgés en premier (coût de production, pas d'exécution). Vous pouvez le voir si vous ajoutez les colonnes original_costet current_costà votre requête sur sys.dm_exec_cached_plans. Un plan ad hoc commence à 0 et est incrémenté de 1 chaque fois qu'il est utilisé. Lorsque la pression du cache se produit, SQL Server soustrait la moitié de chaque coût, puis purge ceux qui ont atteint 0.

Si vous avez beaucoup de SQL ad-hoc, essayez:

exec sp_reconfigure 'optimize for ad hoc workloads', 1
go
reconfigure
go

Dans ce mode, SQL Server met en cache uniquement un "stub", d'environ 300 octets (un plan de requête normal est de 24 Ko minimum), contenant un hachage et un pointeur vers le texte SQL, la première fois qu'il voit une instruction SQL particulière, puis met ensuite en cache le plan complet s'il est exécuté à nouveau. Cela ne réduira pas nécessairement les compilations en soi, mais cela allégera la pression de la mémoire sur le cache du plan.

Remarque: Cela fonctionne en 2008, pas essayé en 2005.

Une autre astuce est

alter database ... set parameterization forced
go

Cela entraînera SQL Server à traiter les constantes comme des paramètres, ce qui peut aider la fonctionnalité de paramétrage automatique qui met généralement en cache les plans d'instructions SQL similaires. Le SQL ad-hoc devrait avoir ses plans de requête mis en cache, sauf si votre serveur manque de mémoire, mais cela s'appuie sur des correspondances textuelles exactes à moins qu'il ne puisse être paramétré, auquel cas il se comporte plus comme une requête préparée.

Gaius
la source
Merci! Je connaissais cette option de "paramétrage forcé" mais j'avais peur de l'utiliser. Le seul inconvénient que je peux voir en utilisant ceci est qu'il remplira le cache. Ai-je raison?
Manjot
3

Avez-vous de nombreux travaux SQL Server exécutés fréquemment sur cette zone? Notez qu'en 2005, les requêtes de travail d'agent ne sont PAS mises en cache et peuvent également provoquer les compilations de saturation et sql du cache.

Regardez le nombre de plans avec un faible nombre de réutilisation. Ce sont vos coupables.

Quelques notes connexes sur la mise en cache du plan ci-dessous.

http://www.sqlskills.com/BLOGS/KIMBERLY/post/Plan-cache-adhoc-workloads-and-clearing-the-single-use-plan-cache-bloat.aspx

http://www.sqlskills.com/BLOGS/KIMBERLY/post/Clearing-the-cache-are-there-other-options.aspx

Sankar Reddy
la source
0

Cet effet est connu sous le nom de «pollution du plan de requête», où de nombreuses requêtes SQL similaires génèrent des plans d'exécution distincts mais équivalents.

Les requêtes ad hoc entraînent des frais généraux par analyse individuelle, mais généralement pas la pollution du plan de requête, car leurs plans ne sont pas stockés. Ceci est différent pour les requêtes avec un seul paramètre (sous MS SQL Server), celles-ci seront traitées comme une requête paramétrée.

Il existe des cas typiques de pollution du plan de requête:

  • Requêtes SQL avec un seul paramètre littéral codé en dur (comme 'select id, name from person where id = 1234')
  • surtout s'il est utilisé avec des commandes / procédures stockées qui forcent la base de données à stocker le plan de requête, comme 'sp_prepexec' ou sp_executesql 'sous MSSQL (je pense que' exécuter immédiatement 'sous Oracle fonctionne de la même manière)
  • requêtes partiellement paramétrées, avec une grande variance dans les valeurs littérales 'codées en dur', telles que 'select * from SoccerMatches sm où sm.Date>?' et sm.Date <? et HomeClubId = 5678 et GuestClubId = 1234 '. Ceux-ci enregistreront les plans de requête en raison des paramètres, mais créeront un nouveau plan de requête pour chaque HomeClub ou GuestClub modifié (en particulier, car les valeurs Date / Heure sont une excellente occasion d'introduire des paramètres dans de nombreuses API de base de données, lorsque les requêtes échouent en raison d'une date localement différente. formats).
  • Une autre source de pollution du plan de requête peut être des frameworks comme ADO.NET avec des pilotes insuffisants, en combinaison avec des valeurs varchar string / (n). Certaines implémentations / pilotes définiront la taille des paramètres sur la longueur de chaîne réelle, provoquant un plan de requête distinct pour chaque longueur de paramètre de chaîne différente dans la requête. La meilleure pratique semble être l'utilisation de la taille maximale du champ (par exemple varchar (4000)), ou un pilote qui met une longueur correcte
Erik Hart
la source