web-dev-qa-db-fra.com

Query pour trouver des détails sur le plan pour une procédure stockée spécifique, la recherche par nom

J'essaie d'écrire une requête pour trouver des informations sur les statistiques de requête et le plan de requête pour une procédure stockée spécifique, mais je ne parviens pas à trouver la bonne DMV ou la requête pour rechercher une procédure stockée spécifique.

Jusqu'à présent j'ai:

select
    qs.sql_handle
    , qs.statement_start_offset
    , qs.statement_end_offset
    , qs.plan_handle
    , execution_count
    , st.text
    , substring(st.text, (qs.statement_start_offset/2)+1,
        ((case qs.statement_end_offset
            when -1
                then datalength(st.text)
            else
                qs.statement_end_offset
            end - qs.statement_start_offset) / 2 + 1)) as [Filtered text]
    , qp.query_plan
from sys.dm_exec_query_stats as qs
    cross apply sys.dm_exec_sql_text (qs.sql_handle) as st
    cross apply sys.dm_exec_query_plan (qs.plan_handle) as qp
where st.text like '%myProcedure%'
order by qs.sql_handle
    , execution_count desc

Mais cette requête ne renvoie aucune information. Idéalement, je remplacerais la condition st.text like avec quelque chose comme object_name(procedure_id) = 'myProcedure', mais je ne trouve pas la bonne façon de le faire.

Y a-t-il une meilleure façon de le faire?

Je pourrais remplacer la condition dans la clause WHERE avec un qs.sql_handle = 0x000004004040400..etc., mais comment puis-je découvrir le sql_handle pour la procédure? (cette information n'est pas trouvée dans sys.objects ou dans sys.procedures).

Toute information est grandement appréciée.

Mise à jour :

J'ai exécuté la procédure (exec myProcedure ...) dans un environnement de test et maintenant, il est renvoyé par la requête ci-dessus et je peux donc obtenir la poignée du plan pour utiliser le where sql_handle = 0x0034300.., mais j'aimerais exécuter la même requête d'en haut en production, sans avoir à exécuter la procédure en production (juste pour connaître sa poignée de plan).

C'est la raison pour laquelle j'essaie d'écrire la requête de cette manière pour obtenir les informations basées sur le nom, pas sql_handle (juste parce que dans le prod que je ne sais pas quel est son sql_handle).

4
Radu Gheorghiu

Étant donné que le DMV de sys.dm_exec_query_stats renvoie des données pour l'ensemble de l'instance, vous devez être capable d'obtenir un schéma d'objet et des informations de nom dans toutes les bases de données. Utilisation de ST.objectid = OBJECT_ID(N'dbo.ProcedureName'), comme cela a été suggéré, est sujettes à l'erreur car elle ne résoudra que le nom relatif à la base de données dans laquelle la requête est exécutée:

  1. Si le nom d'objet n'existe pas dans cette base de données, il retournera NULL, qui fera filtrer toutes les lignes.
  2. Si le nom de l'objet existe dans cette base de données, mais que vous souhaitez réellement que le nom d'objet dans une base de données différente, vous obtiendrez une valeur object_id__ que Peut-être Soyez correct, mais pourrait tout aussi bien). un objet différent et peut renvoyer une ou plusieurs lignes incorrectes.
  3. Si une valeur object_id est renvoyée, si elle est correcte ou incorrecte, cette valeur particulière peut exister sur plusieurs bases de données et de récupérer plusieurs rangées pour différents objets dans différentes bases de données.

À tout le moins, vous auriez besoin de fournir un nom d'objet entièrement qualifié (nommé à trois parties). Cependant, même si vous utilisez OBJECT_ID(N'DatabaseName.SchemaName.ObjectName'), la requête a toujours le potentiel de résoudre le problème n ° 3 noté ci-dessus depuis que object_id, même étant correct, peut exister sur plusieurs bases de données. Donc, vous avez besoin d'une seconde condition en utilisant la fonction DB_ID() fonction pour réduire la base de données envisagée.

WHERE st.[objectid] = OBJECT_ID(N'DatabaseName.SchemaName.ObjectName')
AND   st.[dbid] = DB_ID(N'DatabaseName')

Cependant, ma préférence est d'utiliser le Nom d'objet et Object_schema_name fonctions car ils acceptent tous les deux un 2ème paramètre optionnel pour database_id. L'avantage ici est que vous pouvez les utiliser dans la clause SELECT lorsque vous ne réduisez pas un objet spécifique, de sorte que vous puissiez voir les noms d'objet pour toutes les lignes du DMV. Il permet également de filtrer sur le même objet sur plusieurs bases de données, ce qui est utile lorsque vous avez la même procédure stockée dans plusieurs bases de données et que vous souhaitez voir des lignes pour elle dans toutes les bases de données, même s'il a probablement différentes valeurs de object_id sur ces bases de données.

Par conséquent, vous pouvez éventuellement ajouter ce qui suit à la clause SELECT (J'utilise cela lors de la croix appliquant sys.dm_exec_sql_text sur DMVS tels que sys.dm_exec_requests, etc.):

DB_NAME(st.[dbid]) AS [DatabaseName],
OBJECT_SCHEMA_NAME(st.[objectid], st.[dbid]) AS [SchemaName],
OBJECT_NAME(st.[objectid], st.[dbid]) AS [ObjectName]

Et vous mettriez ensuite à jour votre requête pour avoir la clause WHERE suivante:

WHERE OBJECT_NAME(st.[objectid], st.[dbid]) = N'my_proc_name'
AND   OBJECT_SCHEMA_NAME(st.[objectid], st.[dbid]) = N'dbo' -- or whatever schema
-- AND  DB_NAME(st.[dbid]) = N'DatabaseName' -- optionally narrow down to specific DB
6
Solomon Rutzky

Essayez d'utiliser SYS_DM_EXEC_PROCEDURE_STATS

select object_name(object_id, database_id), * from sys.dm_exec_procedure_stats
where object_name(object_id, database_id) like '%proc name%'
2
Manikantan