web-dev-qa-db-ja.com

名前で検索して、特定のストアドプロシージャのプラン詳細を検索するクエリ

特定のストアドプロシージャのクエリ統計とクエリプランに関する情報を検索するクエリを作成しようとしていますが、特定のストアドプロシージャを検索するための適切なDMVまたはクエリを見つけることができません。

これまでのところ:

_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
_

ただし、このクエリは情報を返しません。理想的には、_st.text like_条件をobject_name(procedure_id) = 'myProcedure'のようなものに置き換えますが、正しい方法を見つけることができません。

そうするためのより良い方法はありますか?

WHERE句の条件を_qs.sql_handle = 0x000004004040400..etc._で置き換えることができますが、プロシージャの_sql_handle_を見つけるにはどうすればよいですか? (この情報は_sys.objects_または_sys.procedures_にはありません)。

どんな情報でも大歓迎です。

更新:

プロシージャ(_exec myProcedure ..._)をテスト環境で実行し、上記のクエリによって返されたので、プランハンドルを取得して_where sql_handle = 0x0034300.._を使用できますが、実行したいと思います本番環境で上記の同じクエリを実行します(本番環境でプロシージャを実行する必要はありません(プランハンドルを見つけるため))。

これが、_sql_handle_ではなく名前に基づいて情報を取得するためにこのようにクエリを記述しようとしている理由です(製品では、_sql_handle_が何であるかわからないため) 。

4
Radu Gheorghiu

_sys.dm_exec_query_stats_ DMVがインスタンス全体のデータを返すとすると、すべてのデータベースにわたってオブジェクトスキーマと名前の情報を取得できる必要があります。推奨されているようにST.objectid = OBJECT_ID(N'dbo.ProcedureName')を使用すると、クエリが実行されているデータベースに関連する名前のみが解決されるため、エラーが発生しやすくなります。

  1. オブジェクト名がそのデータベースに存在しない場合は、NULLが返され、すべての行が除外されます。
  2. オブジェクト名がそのデータベースに存在するが、実際には別のデータベースのオブジェクト名が必要な場合は、正しい_object_id_値が得られます正しいしかし、別のオブジェクトを指すだけでなく、1つ以上の誤った行を返す可能性もあります。
  3. _object_id_値が返された場合、正しいか正しくないかにかかわらず、その特定の値は複数のデータベースに存在する可能性があるため、異なるデータベースの異なるオブジェクトに対して複数の行が返される可能性があります。

少なくとも、完全修飾オブジェクト名(つまり、3部構成の名前)を提供する必要があります。ただし、OBJECT_ID(N'DatabaseName.SchemaName.ObjectName')を使用した場合でも、_object_id_が正しい場合でも複数のデータベースに存在する可能性があるため、クエリには上記の問題#3が発生する可能性があります。したがって、目的のデータベースに絞り込むためにDB_ID()関数を使用する2番目の条件が必要です。

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

ただし、どちらも_database_id_のオプションの2番目のパラメーターを受け入れるため、私の好みは OBJECT_NAME および OBJECT_SCHEMA_NAME 関数を使用することです。ここでの利点は、特定のオブジェクトに絞り込んでいないときにSELECT句でそれらを使用できるため、DMVのすべての行のオブジェクト名を確認できることです。また、複数のデータベースにまたがる同じオブジェクトまでフィルタリングすることもできます。これは、複数のデータベースに同じストアドプロシージャがあり、異なる_object_id_値が含まれている可能性がある場合でも、すべてのデータベースにその行を表示する場合に役立ちます。それらのデータベース全体。

したがって、オプションで以下をSELECT句に追加できます(_sys.dm_exec_sql_text_などのDMVに_sys.dm_exec_requests_をクロス適用するときに使用します)。

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

次に、次のWHERE句を含むようにクエリを更新します。

_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

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