SQL Server: 프로덕션 환경에서 현재 사용되지 않는 저장 프로시저를 찾는 방법

배경



프로덕션 환경에서 현재 사용되지 않는 테이블을 찾는 방법 에 대해 이전 기사로 했습니다만, 이것의 스토어드 프로시저판을 정리해 두려고 생각해, 방법을 생각해 보았습니다.

아이디어



dm_exec_procedure_stats이라는 DMV를 사용합니다. 이 DMV는 캐시된 저장 프로시저에 대한 통계 정보를 볼 수 있습니다.

예를 들어, 다음 쿼리를 실행하여 각 저장 프로시저의 최종 실행 시간, 캐시된 이후 누적 실행 횟수 등을 검색할 수 있습니다.
select
  getdate() as collect_date,
  object_name(ps.object_id, ps.database_id) as object_name,
  db_name(ps.database_id) as database_name,
  ps.last_execution_time,
  o.modify_date,
  ps.cached_time,
  ps.execution_count
from
  sys.dm_exec_procedure_stats  as ps
  left join sys.objects as o on o.object_id = ps.object_id
where object_name(ps.object_id, ps.database_id) is not null
and object_name(ps.object_id, ps.database_id) not like 'sp[_]MS%' --レプリ系除外
order by cached_time asc



이 실행 결과를 정기적으로 덤프를 계속하는 것으로, 「실행된 적이 있는 스토어드 프로시저의 리스트」를 만들 수 있습니다. 그런 다음 DB에 있는 저장 프로시저와 비교하여 사용하지 않는 저장 프로시저를 확인할 수 있습니다.

고려점



1. 덤프 간격에 대해서는 "캐시 아웃되지 않을 정도로 짧은 간격"을 지정해야 합니다.
이것은 환경에 따라 달라집니다만, 10초마다 덤프 해 두면 대부분의 환경에서는 캐쉬 아웃 하는 일 없이, 실행된 모든 스토어드 프로시저의 정보를 수집할 수 있다고 생각합니다.
※환경마다 캐쉬 아웃되는 최단 시간을 요구하는 방법에 대해서는 다른 기회로 생각해 정리하고 싶습니다.

2. "얼마나 실행되지 않은 저장 프로시저를 사용하지 않는 것으로 정의할지"도 결정해야 합니다. 월말 월초의 배치 처리가 존재할 가능성을 고려하면, 최소한 「1개월간」이 적당한 기간이라고 생각됩니다.

쿼리



github 에서 공개하고 있습니다.

1. 설문 조사 테이블_create.sql을 한 번만 실행하여 덤프 테이블을 만듭니다.
--[dm_exec_procedure_stats_usage_dump]というテーブルを作成
select
  getdate() as first_insert_date,
  object_name(ps.object_id, ps.database_id) as object_name,
  db_name(ps.database_id) as database_name,
  ps.last_execution_time,
  o.modify_date as last_modify_date,
  o.create_date as create_date,
  ps.cached_time as last_cached_time,
  ps.execution_count as last_execution_count
into dm_exec_procedure_stats_usage_dump
from
  sys.dm_exec_procedure_stats  as ps
  left join sys.objects as o on o.object_id = ps.object_id
where 1=0

--クラスタ化インデックス作成
create clustered index CIX_dm_exec_procedure_stats_usage_dump on dm_exec_procedure_stats_usage_dump(object_name, database_name)

--Unique制約作成
alter table dm_exec_procedure_stats_usage_dump add constraint UQ_dm_exec_procedure_stats_usage_dump unique (object_name, database_name)   

2. 정기적으로(10초-1분간 정도)에 「조사용 테이블_merge.sql」을 실행해 정보를 덤프
set nocount on
merge dm_exec_procedure_stats_usage_dump as target
using (
    select
      getdate() as first_insert_date,
      object_name(ps.object_id, ps.database_id) as object_name,
      db_name(ps.database_id) as database_name,
      ps.last_execution_time,
      o.modify_date,
      o.create_date,
      ps.cached_time,
      ps.execution_count
    from
    (
        --object_idで重複する場合があるため重複カット
        select * from (
            select *, row_number() over(partition by object_id order by last_execution_time desc) as rownum from sys.dm_exec_procedure_stats
        ) as ps
        where rownum = 1
    ) as ps
      left join sys.objects as o on o.object_id = ps.object_id
    where object_name(ps.object_id, ps.database_id) is not null
    and object_name(ps.object_id, ps.database_id) not like 'sp[_]MS%' --レプリ系除外
) as source
on target.object_name = source.object_name
when matched then
    update set last_execution_time = source.last_execution_time
              ,last_modify_date = source.modify_date
              ,create_date = source.create_date --alterでなくdrop+createされるケースを考慮
              ,last_cached_time = source.cached_time
              ,last_execution_count = source.execution_count
when not matched then
    insert (first_insert_date, object_name, database_name, last_execution_time, last_modify_date, create_date, last_cached_time, last_execution_count)
    values (source.first_insert_date, source.object_name, source.database_name, source.last_execution_time, source.modify_date, source.create_date, source.cached_time, source.execution_count)
option (maxdop 1) 
;

※최소라도 1개월간은 정기적으로 덤프를 계속하는 것이 바람직

3. "정보 수집 완료 후 사용되지 않은 저장을 식별하는 쿼리 .sql"을 실행하여 사용되지 않는 저장을 식별합니다.
declare @db_name as nvarchar(1000)
set @db_name = 'master' --未使用ストアドを取得したいDB名をセット
declare @sql nvarchar(max)

set @sql = '
select * from ' + @db_name + '.sys.objects
where name not in (select object_name from dm_exec_procedure_stats_usage_dump where database_name = ''' + @db_name + ''')
and type=''P''
'
execute(@sql)

좋은 웹페이지 즐겨찾기