Nicht verwendete gespeicherte Prozeduren identifizieren

24

Im nächsten Jahr helfe ich bei der Bereinigung mehrerer SQL Server-Umgebungen.

Wir haben ungefähr 10.000 gespeicherte Prozeduren und schätzen, dass nur ungefähr 1000 von ihnen regelmäßig verwendet werden, und weitere 200 werden in seltenen Fällen verwendet, was bedeutet, dass wir viel Arbeit zu erledigen haben.

Da wir über mehrere Abteilungen und Teams verfügen, die auf diese Datenbanken und Prozeduren zugreifen können, werden die Prozeduren nicht immer von uns aufgerufen, sodass wir bestimmen müssen, welche Prozeduren aufgerufen werden. Darüber hinaus möchten wir dies über einige Monate und nicht über einige Tage hinweg feststellen (was einige Möglichkeiten ausschließt).

Ein Ansatz hierfür besteht darin, die SQL Server ProfilerProzeduren zu verwenden und zu verfolgen, welche Prozeduren aufgerufen werden, und sie mit der Liste der verfügbaren Prozeduren zu vergleichen und zu markieren, ob die Prozeduren verwendet werden oder nicht. Ab dann könnten wir die Prozeduren in ein anderes Schema verschieben, falls eine Abteilung schreien sollte.

Ist der Profilereffektivste Ansatz hier? Und / oder hat jemand von euch etwas Ähnliches gemacht und einen anderen / besseren Weg gefunden, dies zu tun?

Question3CPO
quelle

Antworten:

32

Sie können die serverseitige Ablaufverfolgung (anders als die Verwendung der Profiler-GUI, die mehr Ressourcen erfordert) während Ihres Tests oder Ihres Geschäftszyklus verwenden und nur mit SPs zusammenhängende Daten erfassen. Dann können Sie das in eine Tabelle laden oder zur weiteren Analyse auszeichnen.

Der zweite Ansatz ist die Verwendung von DMV sys.dm_exec_procedure_stats (mit der Einschränkung, dass beim Neustart von SQL Server die Daten gelöscht werden).

Sie können sogar einen Job zur Erfassung von DMV-Daten in einer Tabelle einplanen, um die Speicherung aufrechtzuerhalten.

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

Beziehen auf :

Kin Shah
quelle
1
Siehe auch stackoverflow.com/questions/10421439/… und stackoverflow.com/questions/7150900/… (ignoriert, dass auf letzterem der Link zu SQLServerPedia jetzt nicht mehr vorhanden ist).
Aaron Bertrand
2
Stellen Sie sicher, dass Sie die DMV regelmäßig über Wochen oder sogar Monate überprüfen, da es SPs geben kann, die nur monatlich oder sogar vierteljährlich ausgeführt werden. DMVs werden gelöscht, wenn die Instanz neu gestartet, manuell oder im Laufe der Zeit gelöscht wird.
Kenneth Fisher
1
@KennethFisher Deshalb habe ich empfohlen, einen Job zum Erfassen von DMV-Daten in einer Tabelle zu planen. Vielen Dank für die Erwähnung!
Kin Shah
11

Sie finden diese Frage nützlich, sie gilt für Tabellen und Spalten, schlägt jedoch die Verwendung eines Drittanbieter-Tools ApexSQL Clean vor, das auch nicht verwendete gespeicherte Prozeduren sowie alle Objekte findet, auf die von keinem anderen Objekt in der Datenbank oder in externen Datenbanken verwiesen wird

Haftungsausschluss: Ich arbeite für ApexSQL als Support Engineer

Milica Medic
quelle
3
Das OP will nicht finden unreferenced stored procedures, stattdessen will das OP unbenutzten SP finden. Ihre Antwort ist keine Antwort auf diese Frage.
Kin Shah
Kin, ich werde aktualisieren. ApexSQL Clean markiert nicht verwendete Objekte als nicht referenziert, so dass ich verstehe, dass dies die Verwirrung verursachte
Milica Medic
10

Wenn Sie mit SQL Server 2008+ arbeiten, können Sie auch erweiterte Ereignisse mit einem Histogrammziel verwenden . Möglicherweise wäre dies leichter als eine Spur.

AFAIK, Sie müssten jedoch für jede Datenbank von Interesse eine andere Sitzung erstellen, da ich keinen Hinweis darauf sehen konnte, dass ein Bucket-Vorgang für mehrere Spalten möglich war. Das kurze Beispiel unten filtert andatabase_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

Und dann, nachdem einige gespeicherte Prozeduren in dieser Datenbank ein paar Mal ausgeführt und die Daten mit abgerufen wurden

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'

Die Ausgabe ist

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

Daraus geht hervor, dass die Prozedur mit object_idvon1287675635 beispielsweise 36 Mal ausgeführt wurde. Der asynchronous_bucketizerSpeicher ist nur so dass es am besten wäre , etwas , dass Umfragen dies jeder so oft einzurichten und spart bis zu persistenten Speicher.

Martin Smith
quelle
1
Es ist wahr, Sie benötigen eine Sitzung pro Datenbank. Wäre toll zu sagen, WHERE (source_database_id IN (10,15,20))aber leider wird dies nicht unterstützt.
Aaron Bertrand
@AaronBertrand - Und selbst wenn es unterstützt würde, müssten Sie Prozeduraufrufe für Objekte mit demselben object_id(oder demselben object_name) in verschiedenen Datenbanken separat zählen, und ich denke, dass dies auch nicht möglich ist.
Martin Smith
Korrigiere mich, wenn ich falsch liege, aber extended eventswo wurde 2012 nicht 2008 hinzugefügt?
Peter
1
@ Peter yep du bist falsch. :-) technet.microsoft.com/en-us/library/dd822788(v=sql.100).aspx
Martin Smith
1
Die erweiterte Ereignis-Benutzeroberfläche wurde erst in SSMS 2012 eingeführt, und ich glaube nicht, dass sie abwärtskompatibel gemacht wurde. Im Jahr 2008 war die einzige Möglichkeit, sofort Sitzungen zu erstellen, TSQL, obwohl es ein Community-Projekt für ähnliche Funktionen gab. Extendedeventmanager.codeplex.com
Martin Smith
4

Als Fortsetzung von Kins Drehbuch. Hier ist ein einfaches Skript zum Erstellen einer Tabelle zum Verfolgen der Verwendung im Laufe der Zeit und ein Skript zum regelmäßigen Aktualisieren.

--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--  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
James White
quelle
0

Dieser Beitrag enthält auch ein Skript zum Auffinden nicht verwendeter Objekte: Auffinden nicht verwendeter Datenbanktabellen in SQL Server Unten ist das Skript aus dem Artikel zu sehen, ich habe den Tabellentyp "U" in den Typ "P" für gespeicherte Prozeduren geändert:

   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
Milica Medic
quelle
Dies gibt immer alle Prozeduren zurück, da Prozeduren keine Einträge in der Indexnutzungsstatistik DMV erhalten ...
Martin Smith