Визначення невикористаних збережених процедур


24

У наступному році я допомагаю очистити декілька середовищ SQL Server.

У нас є близько 10 000 збережених процедур і підрахуємо, що лише близько 1000 з них використовуються регулярно, а ще близько 200 використовуються рідко, це означає, що нам належить зробити багато роботи.

Оскільки у нас є декілька відділів і команд, які можуть отримати доступ до цих баз даних і процедур, ми не завжди називаємо ці процедури, це означає, що ми повинні визначати, які процедури викликаються. Крім цього, ми хочемо визначити це за кілька місяців, а не за кілька днів (що виключає деякі можливості).

Один із підходів до цього - використовувати SQL Server Profilerта відстежувати, які процедури викликаються, та порівнювати їх із переліком процедур, які ми маємо, при цьому відмічаючи, використовуються вони чи ні. З цього моменту ми могли б перенести процедури на іншу схему, якщо відділ кричить.

Чи використовується Profilerтут найефективніший підхід? І / чи хтось із вас зробив щось подібне і знайшов інший / кращий спосіб зробити це?

Відповіді:


32

Ви можете використовувати трасування на стороні сервера (відмінне від використання графічного інтерфейсу Profiler, який залучає більше ресурсів) під час тестування або у вашому бізнес-циклі та захоплювати лише речі, пов’язані з SP. Потім ви можете завантажити це в таблицю або переконатись для подальшого аналізу.

Другий підхід - використовувати 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
Переконайтесь, що ви періодично перевіряєте DMV протягом тижнів чи навіть місяців, оскільки можуть виникнути SP, які запускаються лише щомісяця або навіть щоквартально. DMV очищаються при перезапуску примірника, очищенні вручну або навіть просто з часом.
Кеннет Фішер

1
@KennethFisher Ось чому я рекомендував запланувати роботу зі збору даних DMV до таблиці. Дякуємо, що згадуєте!
Кін Шах

11

Ви можете вважати це питання корисним, воно стосується таблиць і стовпців, але пропонує використовувати сторонній інструмент ApexSQL Clean, який також може знайти невикористані збережені процедури, а також усі об'єкти, на які не посилається жоден інший об'єкт у базі даних або у зовнішніх базах даних

Відмова від відповідальності: Я працюю в ApexSQL як інженер підтримки


3
ОП не хоче знайти unreferenced stored procedures, натомість ОП хочуть знайти невикористані ІП. Ваша відповідь не служить відповіддю на це питання.
Кін Шах

Кін, я оновлю. ApexSQL Clean відзначає невикористані об'єкти як невиправлені, тому я розумію, що це спричинило плутанину
Milica Medic

10

Якщо ви перебуваєте на SQL Server 2008+, ви також можете використовувати розширені події з ціллю гістограми . Можливо, це було б більше легкої ваги, ніж сліду.

AFAIK, вам потрібно буде створити різний сеанс для кожної цікавої бази даних, хоча, як я не міг бачити жодних ознак того, що можливий перепрошивка в декількох стовпцях. Короткий приклад, наведений нижче, фільтрує на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

А потім після запуску деяких збережених процедур у цій БД кілька разів та отримання даних за допомогою

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_idз 1287675635була виконана 36 разів, наприклад. Це asynchronous_bucketizerлише пам'ять, тому найкраще було б налаштувати щось таке, яке опитується так часто і економить для постійного зберігання.


1
Це правда, вам потрібно один сеанс на базу даних. Було б чудово сказати, WHERE (source_database_id IN (10,15,20))але, на жаль, це не підтримується.
Аарон Бертран

@AaronBertrand - І навіть якщо він був підтриманий, вам все одно потрібно буде рахувати процедурні виклики для об'єктів з однаковими object_id(або однаковими object_name) в різних базах даних окремо, і я не думаю, що це також можливо.
Мартін Сміт

Виправте мене, якщо я помиляюся, але extended eventsде додано в 2012 році, а не в 2008 році?
Пітер

1
@ Петер да, ви помиляєтесь. :-) technet.microsoft.com/en-us/library/dd822788(v=sql.100).aspx
Мартін Сміт

1
Інтерфейс розширених подій не був представлений до SSMS 2012, і я не думаю, що вони зробили його назад сумісним. У 2008 році єдиний спосіб створення сесій поза коробки був через TSQL хоча був спільний проект для подібної функціональності extendedeventmanager.codeplex.com
Мартін Сміт

4

Як продовження сценарію Кіна. Ось простий скрипт для створення таблиці для відстеження використання за часом та сценарій для періодичного оновлення.

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

Це повідомлення також надає скрипт , щоб знайти невикористовувані ojects: Знайти невикористовувані таблиці бази даних в 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

Це завжди повертає всі процедури, оскільки процедури не отримують записи в статистиці використання індексу DMV ...
Martin Smith
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.