未使用のストアドプロシージャの特定


24

来年、私はいくつかのSQL Server環境をきれいにする取り組みを支援しています。

約10,000のストアドプロシージャがあり、そのうちの約1000のみが定期的に使用され、別の200程度がまれに使用されると推定されます。つまり、やるべきことがたくさんあります。

これらのデータベースとプロシージャにアクセスできる複数の部門とチームがあるため、常にプロシージャを呼び出しているわけではありません。つまり、どのプロシージャが呼び出されているかを判断する必要があります。それに加えて、数日ではなく、数か月でこれを判断します(いくつかの可能性を排除します)。

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

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

回答:


32

あなたは使用することができ、サーバー側のトレース あなたのテストや、あなたのビジネスサイクルの間(招き、より多くのリソースというプロファイラGUIを使用して異なるが)とSPのに関連しただけのものをキャプチャします。次に、それをテーブルにロードするか、さらに分析するために優れています。

2番目のアプローチは、DMV sys.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;

参照する :


1
stackoverflow.com/questions/10421439/…およびstackoverflow.com/questions/7150900/…も参照してください(後者では、SQLServerPediaへのリンクは現在無効になっています)。
アーロンバートランド

2
月単位または四半期単位でのみ実行されるSPが存在する場合があるため、数週間または数か月間にわたって定期的にDMVを確認してください。DMVは、インスタンスの再起動、手動でのクリア、または時間の経過とともにクリアされます。
ケネスフィッシャー

1
@KennethFisherそれで、DMVデータをテーブルにキャプチャするジョブをスケジュールすることをお勧めします。言及してくれてありがとう!
キンシャー

11

あなたは見つけることができます。この質問は、それはまた、未使用のストアドプロシージャと同様に、データベース内、または外部データベースに他のオブジェクトによって参照されていないすべてのオブジェクトを見つけることができるサードパーティ製のツールApexSQLクリーンを使用してテーブルと列に適用されるが示唆して、便利

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


3
OPは検索を望んでおらずunreferenced stored procedures、代わりにOPは未使用のSPを検索したいと考えています。あなたの答えは、この質問に対する答えとしては機能しません。
キンシャー

キン更新します。私はそれが混乱を引き起こしたことを理解して参照されていないとして、ApexSQLクリーンマーク、未使用のオブジェクトを
ミリカメディック

10

SQL Server 2008以降を使用している場合は、ヒストグラムターゲットで拡張イベントを使用することもできます。おそらくこれは、トレースよりも軽量です。

私は複数の列のバケット化が可能であるという兆候を見ることができなかったので、興味のあるデータベースごとに異なるセッションを作成する必要があります。以下の簡単な例は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>

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


1
確かに、データベースごとに1つのセッションが必要です。素晴らしいことですがWHERE (source_database_id IN (10,15,20))、残念ながらこれはサポートされていません。
アーロンバートランド

@AaronBertrand-サポートされていても、異なるデータベースで同じobject_id(または同じobject_name)のオブジェクトのプロシージャ呼び出しを個別にカウントする必要があり、それも可能だとは思いません。
マーティンスミス

私が間違っているがextended events、2008年ではなく2012年にどこに追加されたのですか?
ピーター

1
@Peterうん、あなたは間違っている。:-) technet.microsoft.com/en-us/library/dd822788(v=sql.100).aspx
マーティンスミス

1
拡張イベントUIは、SSMS 2012まで導入されていなかったため、下位互換性を持たせたとは思いません。2008年に、TSQLを使用してセッションを作成する唯一の方法はTSQLを使用することでしたが、同様の機能のコミュニティプロジェクトがありましたextendedeventmanager.codeplex.com
Martin Smith

4

Kinのスクリプトの続きとして。これは、時間の経過とともに使用状況を追跡するテーブルを作成する簡単なスクリプトと、定期的に更新するスクリプトです。

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

0

この投稿では、未使用のオブジェクトを検索するスクリプトも提供しています。SQLServerで未使用のデータベーステーブルを検索する 以下は記事のスクリプトです。

   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

インデックスの使用で作られたエントリを取得しない手順がDMV ...統計としてこれは常に、すべての手続きを返します
マーティン・スミス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.