Identificazione delle procedure memorizzate non utilizzate


24

L'anno prossimo sto aiutando a ripulire diversi ambienti di SQL Server.

Abbiamo circa 10.000 procedure memorizzate e stimiamo che solo circa 1000 di esse vengano utilizzate su base regolare e altre 200 circa in rare occasioni, il che significa che abbiamo molto lavoro da fare.

Poiché abbiamo più dipartimenti e team che possono accedere a questi database e procedure, non siamo sempre quelli che chiamano le procedure, il che significa che dobbiamo determinare quali procedure vengono chiamate. Inoltre, vogliamo determinarlo in pochi mesi, non in pochi giorni (il che elimina alcune possibilità).

Un approccio a questo è quello di utilizzare SQL Server Profilere tenere traccia delle procedure che vengono chiamate e confrontarle con l'elenco di quali procedure abbiamo, evidenziando al contempo se le procedure vengono utilizzate o meno. Da allora, potremmo spostare le procedure su uno schema diverso nel caso in cui un reparto urli.

Usando l' Profilerapproccio più efficace qui? E / o qualcuno di voi ha fatto qualcosa di simile e ha trovato un altro modo / modo migliore per farlo?

Risposte:


32

È possibile utilizzare la traccia lato server (diversa dall'utilizzo della GUI di Profiler che comporta maggiori risorse) durante i test o il ciclo aziendale e acquisire solo elementi correlati agli SP. Quindi puoi caricarlo in una tabella o eccellere per ulteriori analisi.

Secondo approccio, utilizzare DMV sys.dm_exec_procedure_stats (con la limitazione che se il server sql viene riavviato, i dati vengono scaricati).

È anche possibile pianificare un lavoro per acquisire i dati DMV su una tabella per mantenerli persistenti.

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

Fare riferimento a:


1
Vedi anche stackoverflow.com/questions/10421439/… e stackoverflow.com/questions/7150900/… (ignorando che su quest'ultimo il collegamento a SQLServerPedia è ora morto).
Aaron Bertrand

2
Assicurati di controllare periodicamente il DMV nel corso di settimane o addirittura mesi poiché potrebbero esserci SP che vengono eseguiti solo su base mensile o addirittura trimestrale. I DMV vengono cancellati quando l'istanza viene riavviata, cancellata manualmente o anche solo nel tempo.
Kenneth Fisher,

1
@KennethFisher Ecco perché ho consigliato di pianificare un lavoro per acquisire dati DMV su una tabella. Grazie per averlo menzionato!
Kin Shah,

11

Puoi trovare questa domanda utile, si applica a tabelle e colonne ma suggerisce di utilizzare uno strumento di terze parti ApexSQL Clean che può anche trovare procedure memorizzate inutilizzate e tutti gli oggetti a cui non fa riferimento nessun altro oggetto nel database o in database esterni

Disclaimer: lavoro per ApexSQL come tecnico dell'assistenza


3
L'OP non vuole trovare unreferenced stored procedures, invece l'OP vuole trovare SP inutilizzati. La tua risposta non serve come risposta a questa domanda.
Kin Shah,

Kin, aggiornerò. ApexSQL Clean contrassegna gli oggetti inutilizzati come non referenziati, quindi capisco che ciò ha causato confusione
Milica Medic

10

Se si utilizza SQL Server 2008+, è possibile utilizzare anche eventi estesi con una destinazione dell'istogramma . Forse questo sarebbe più leggero di una traccia.

AFAIK avresti bisogno di creare una sessione diversa per ogni database di interesse, dato che non riuscivo a vedere alcuna indicazione che fosse possibile seccare su più colonne. Il rapido esempio di seguito si attivadatabase_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

E poi dopo aver eseguito alcune procedure memorizzate in quel DB alcune volte e aver recuperato i dati con

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'

L'output è

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

Mostrando che la procedura con object_idof è 1287675635stata eseguita 36 volte, ad esempio. La asynchronous_bucketizermemoria è solo quindi sarebbe meglio impostare qualcosa che lo scruti ogni tanto e salvi in ​​memoria persistente.


1
È vero, è necessaria una sessione per database. Sarebbe bello da dire, WHERE (source_database_id IN (10,15,20))ma purtroppo questo non è supportato.
Aaron Bertrand

@AaronBertrand - E anche se fosse supportato, dovresti comunque contare le chiamate di procedura per oggetti con lo stesso object_id(o stesso object_name) in database diversi separatamente e non penso che sia possibile neanche.
Martin Smith,

Correggimi se sbaglio ma extended eventsdove aggiunto nel 2012 non nel 2008?
Peter,


1
L'interfaccia utente degli eventi estesi non è stata introdotta fino a SSMS 2012 e non credo che l'abbiano resa compatibile con le versioni precedenti. Nel 2008 l'unico modo per creare sessioni out-of-the-box era attraverso TSQL sebbene ci fosse un progetto della comunità per funzionalità simile extendedeventmanager.codeplex.com
Martin Smith

4

Come seguito alla sceneggiatura di Kin. Ecco un semplice script per creare una tabella per tenere traccia degli usi nel tempo e uno script per aggiornarlo periodicamente.

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

Questo post fornisce anche uno script per trovare gli oggetti inutilizzati: Trova le tabelle del database inutilizzate in SQL Server Di seguito è riportato lo script dell'articolo, ho cambiato il tipo di tabella "U" nel tipo di procedura memorizzata "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

Ciò restituirà sempre tutte le procedure poiché le procedure non ottengono le voci inserite nelle statistiche di utilizzo dell'indice DMV ...
Martin Smith
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.