Tips for DBA: The Spy for stored procedures

Источник: msmvps

Вашему вниманию предлагается макет сценария и методики, позволяющей организовать учёт исполнения хранимых процедур пользовательской базы данных. Пример сценария само-достаточен, т.е. для его успешной работы необходимо только заменить в тексте сценария слово 'ТУТ ДОЛЖНО БЫТЬ ИМЯ ВАШЕЙ БАЗЫ ДАННЫХ!!!!!!!!!!!!!!!!' на имя вашей базы данных, использование процедур которой необходимо отслеживать. Сценарий создаёт задание Агента SQL Server, которое по установленному расписанию (расписание подбирается в зависимости от нагрузки сервера) исполняет сценарий T-SQL. Исполняемый заданием сценарий создаёт по необходимости в базе TEMPDB таблицу Activproc, и потом записывает в ней статистику использования процедур, получая актуальные на момент исполнения метаданные сервера. Для того, чтобы понять принципы работы сценария, ознакомьтесь с теми разделами BOL, в которых описаны задействованные в сценарии административные динамические представления и функции.

Предлагаемая методика отслеживания активности процедур не гарантирует 100% точности собираемой статистики. Она полагается на то, что метаданные об исполнении процедур будут достаточно долго доступны и попадут в таблицу. Для сильно нагруженных серверов этого может не произойти. Однако, преимуществом этой методики является тот факт, что она не так нагружает сервер, как трассировка.

В примере сценария местом размещения таблицы статистики процедур выбрана база данных TEMPDB. Этот факт нужно учитывать, поскольку при каждом запуски службы SQL Server эта база данных создаётся заново, и информация в таблице статистики будет утеряна.

Пример сценария:

    USE [msdb]
    GO
    DECLARE @jobId BINARY(16)
    
    EXEC msdb.dbo.sp_add_job @job_name=N'Activproc', 
    	@enabled=1, 
    	@notify_level_eventlog=0, 
    	@notify_level_email=2, 
    	@notify_level_netsend=0, 
    	@notify_level_page=0, 
    	@delete_level=0, 
    	@description=N'Собирает простую статистику по использованию хранимых процедур', 
    	@category_name=N'Database Maintenance', 
    	@owner_login_name=N'sa', 
    --	@notify_email_operator_name=N'MS-SQL-Admins', 
    	@job_id = @jobId OUTPUT
    		
    EXEC msdb.dbo.sp_add_jobstep @job_id=@jobId, 
    	@step_name=N'Activproc 1', 
    	@step_id=1, 
    	@cmdexec_success_code=0, 
    	@on_success_action=1, 
    	@on_success_step_id=0, 
    	@on_fail_action=2, 
    	@on_fail_step_id=0, 
    	@retry_attempts=0, 
    	@retry_interval=0, 
    	@os_run_priority=0, 
    	@subsystem=N'TSQL', 
    	@command=N'IF NOT EXISTS (SELECT * FROM tempdb.sys.objects WHERE name = ''Activproc'')
    CREATE TABLE tempdb.[dbo].[Activproc]
    	(
    		[SP_Name] sysname NOT NULL,
    		[last_execution_time] datetime NOT NULL,
    		[avg_elapsed_time_sec] money NOT NULL
    	)
    DECLARE @SP_Name sysname, @last_execution_time datetime, @avg_elapsed_time_sec money
    DECLARE c_Activproc CURSOR GLOBAL FAST_FORWARD READ_ONLY FOR
    SELECT TOP 100 PERCENT    OBJECT_NAME(s.objectid,s.dbid) AS SP_Name
    			, MAX(st.last_execution_time) AS last_execution_time
    			, SUM(CAST((st.total_elapsed_time * 1.0 /100000)/st.execution_count AS money)) 
    			  AS avg_elapsed_time_sec
             FROM master.sys.dm_exec_cached_plans AS c
      CROSS APPLY master.sys.dm_exec_query_plan (c.plan_handle) AS q
       INNER JOIN master.sys.dm_exec_query_stats AS st
               ON c.plan_handle = st.plan_handle
      CROSS APPLY master.sys.dm_exec_sql_text(sql_handle) AS s
            WHERE c.cacheobjtype = ''Compiled Plan''
              AND c.objtype = ''Proc''
              AND q.dbid = DB_ID()
         GROUP BY DB_NAME(q.dbid),OBJECT_NAME(s.objectid,s.dbid)  
         ORDER BY avg_elapsed_time_sec DESC
    
    OPEN GLOBAL c_Activproc
    WHILE 1 = 1
    BEGIN
    	FETCH c_Activproc INTO @SP_Name, @last_execution_time, @avg_elapsed_time_sec
    	IF @@fetch_status <> 0 BREAK
    	IF @SP_Name NOT IN (SELECT SP_Name FROM tempdb.dbo.Activproc WHERE SP_Name = @SP_Name)
    	BEGIN
    		INSERT INTO tempdb.dbo.Activproc (SP_Name, last_execution_time, avg_elapsed_time_sec) 
    		VALUES (@SP_Name, @last_execution_time, @avg_elapsed_time_sec)
    	END
    	ELSE
    	BEGIN
    		UPDATE tempdb.dbo.Activproc 
    		SET last_execution_time = @last_execution_time, avg_elapsed_time_sec = @avg_elapsed_time_sec
    		WHERE SP_Name = @SP_Name
    	END
    END
    CLOSE GLOBAL c_Activproc
    DEALLOCATE c_Activproc
    GO', 
    	@database_name=N'ТУТДОЛЖНОБЫТЬИМЯВАШЕЙБАЗЫДАННЫХ!!!!!!!!!!!!!!!!', 
    	@flags=4
    EXEC msdb.dbo.sp_update_job @job_id=@jobId, 
    	@start_step_id = 1
    EXEC msdb.dbo.sp_add_jobschedule @job_id=@jobId, 
    	@name=N'1', 
    	@enabled=1, 
    	@freq_type=4, 
    	@freq_interval=1, 
    	@freq_subday_type=4, 
    	@freq_subday_interval=1, 
    	@freq_relative_interval=0, 
    	@freq_recurrence_factor=0, 
    	@active_start_date=20090217, 
    	@active_end_date=99991231, 
    	@active_start_time=0, 
    	@active_end_time=235959, 
    --	@schedule_uid=N'ffb0a0d2-93bc-49d0-9fc7-4e35140bfd9f'
    EXEC msdb.dbo.sp_add_jobserver @job_id=@jobId, 
    	@server_name = N'(local)'
    GO
    

Следующий сценарий позволяет запросить статистику использования хранимых процедур:

    SELECT   [SP_Name]
            ,[last_execution_time]
            ,[avg_elapsed_time_sec]
        FROM [tempdb].[dbo].[Activproc]
    ORDER BY [avg_elapsed_time_sec] DESC
    GO
    

Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=22989