web-dev-qa-db-ja.com

未使用のストアドプロシージャの識別

来年、私はいくつかのSQL Server環境をクリーンアップする取り組みを支援しています。

ストアドプロシージャは約10,000あり、定期的に使用されるのは約1000のみで、まれに200程度が使用されると見積もられているため、多くの作業が必要です。

これらのデータベースと手順にアクセスできる複数の部門とチームがあるため、手順を呼び出すのは常にではありません。つまり、呼び出される手順を決定する必要があります。さらに、数日ではなく数か月でこれを特定したいと考えています(これにより、いくつかの可能性が排除されます)。

これに対する1つのアプローチは、SQL Server Profiler呼び出されているプロシージャを追跡し、プロシージャが使用されているかどうかをマークしながら、それらを現在のプロシージャのリストと比較します。それから、部門が叫んだ場合に備えて、手順を別のスキーマに移動できます。

ここでProfilerを使用するのが最も効果的な方法ですか?そして/またはあなたは誰かが同じようなことをしていて、これを行う別の方法/より良い方法を見つけましたか?

25
Question3CPO

テストまたはビジネスサイクル中に サーバーサイドトレース (より多くのリソースを必要とするプロファイラーGUIの使用とは異なります)を使用して、SPに関連するもののみをキャプチャできます。次に、それをテーブルまたはExcelにロードして、さらに分析できます。

2番目のアプローチは、DMVsys.dm_exec_procedure_statsを使用することです(ただし、SQLサーバーが再起動された場合、データはフラッシュされます)。

DMVデータをテーブルにキャプチャして永続化するジョブをスケジュールすることもできます。

 -- Get list of possibly unused SPs (SQL 2008 only)
    SELECT p.name AS 'SP Name'        -- Get list of all SPs in the current database
    FROM sys.procedures AS p
    WHERE p.is_ms_shipped = 0

    EXCEPT

    SELECT p.name AS 'SP Name'        -- Get list of all SPs from the current database 
    FROM sys.procedures AS p          -- that are in the procedure cache
    INNER JOIN sys.dm_exec_procedure_stats AS qs
    ON p.object_id = qs.object_id
    WHERE p.is_ms_shipped = 0;

参照する :

33
Kin Shah

あなたは見つけることができます この質問 便利です、それはテーブルと列に適用されますが、未使用のストアドプロシージャや、データベース、または外部データベース

免責事項:私はApexSQLでサポートエンジニアとして働いています

11
Milica Medic

SQL Server 2008以降を使用している場合は、拡張イベントを histogram target で使用することもできます。おそらく、これはトレースよりも軽量になるでしょう。

私の知る限り、複数の列でバケット化が可能であるという兆候が見られなかったため、関心のあるデータベースごとに異なるセッションを作成する必要があります。以下の簡単な例は、database_id=10でフィルタリングします

CREATE EVENT SESSION [count_module_start_database_10]
ON SERVER
ADD EVENT sqlserver.module_start
(  
        WHERE (source_database_id=10) 
)
ADD TARGET package0.asynchronous_bucketizer
(     SET  filtering_event_name='sqlserver.module_start', 
            source_type=0, 
            source='object_id',
            slots = 10000
)
WITH (MAX_DISPATCH_LATENCY = 5 SECONDS)
GO
ALTER EVENT SESSION [count_module_start_database_10]
ON SERVER
STATE=START

そして、そのDBでいくつかのストアドプロシージャを数回実行し、次のコマンドでデータを取得した後

SELECT CAST(target_data as XML) target_data
FROM sys.dm_xe_sessions AS s 
JOIN sys.dm_xe_session_targets t
    ON s.address = t.event_session_address
WHERE s.name = 'count_module_start_database_10'

出力は

<HistogramTarget truncated="0" buckets="16384">
  <Slot count="36">
    <value>1287675635</value>
  </Slot>
  <Slot count="3">
    <value>1271675578</value>
  </Slot>
  <Slot count="2">
    <value>1255675521</value>
  </Slot>
</HistogramTarget>

たとえば、object_id1287675635のプロシージャが36回実行されたことを示します。 asynchronous_bucketizerはメモリのみであるため、これを頻繁にポーリングして永続ストレージに保存するものをセットアップするのが最善です。

10
Martin Smith

キンのスクリプトの続きとして。時間の経過とともに使用状況を追跡するためのテーブルを作成する簡単なスクリプトと、定期的に更新するスクリプトを次に示します。

--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--  Create the use table 
--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CREATE TABLE [dbo].[_ProcedureUseLog](
    [ObjectName] [nvarchar](255) NOT NULL,
    [UseCount] [int] NULL,
    [LastUse] [datetime] NULL,
    [LastCache] [datetime] NULL,
 CONSTRAINT [PK___PROCEDURE_USE] PRIMARY KEY CLUSTERED 
(
    [ObjectName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[_ProcedureUseLog] ADD  CONSTRAINT [DF_Table_1_References]  DEFAULT ((0)) FOR [UseCount]
GO

--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--  Run this periodically to update the usage stats
--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DECLARE @UsesTable TABLE
(
    ObjectName nvarchar(255),
    Executions int,
    LastUse datetime,
    LastCache datetime
)

INSERT INTO @UsesTable       
SELECT p.name, qs.execution_count, qs.last_execution_time, qs.cached_time
FROM    sys.procedures AS p LEFT OUTER JOIN
        sys.dm_exec_procedure_stats AS qs ON p.object_id = qs.object_id
WHERE        (p.is_ms_shipped = 0)

MERGE [dbo].[_ProcedureUseLog]      AS [Target]
USING @UsesTable                    AS [Source]
    ON Target.ObjectName = Source.ObjectName
WHEN MATCHED AND 
        ( Target.LastCache <> Source.LastCache)
    THEN UPDATE SET
        Target.UseCount = Target.UseCount + Source.Executions,
        Target.LastCache = Source.LastCache,
        Target.LastUse = Source.LastUse
WHEN NOT MATCHED
    THEN INSERT (ObjectName, UseCount, LastUse, LastCache) 
    VALUES      (ObjectName, Executions, LastUse, LastCache);

--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--  This just shows what you've logged so far
--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SELECT * FROM [_ProcedureUseLog] ORDER BY UseCount DESC
4
James White

この投稿では、未使用のオブジェクトを検索するスクリプトも提供しています: SQL Serverで未使用のデータベーステーブルを検索します 以下は、記事のスクリプトです。テーブルのタイプを変更しました " U "からストアドプロシージャタイプ" P "へ:

   USE DBName;
   SELECT 

       ao.[name] [Table],
       s.[name] [Schema],
       [create_date] [Created],
        [modify_date] [LastModified]
    FROM
         sys.all_objects ao JOIN sys.schemas s
           ON ao.schema_id = s.schema_id
    WHERE
         OBJECT_ID NOT IN (
              SELECT OBJECT_ID
              FROM sys.dm_db_index_usage_stats
        )
        AND [type] = 'P'
    ORDER BY
        [modify_date] DESC
0
Milica Medic