Mengidentifikasi Prosedur Tersimpan yang Tidak Digunakan

24

Tahun depan ini, saya membantu upaya untuk membersihkan beberapa lingkungan SQL Server.

Kami memiliki sekitar 10.000 prosedur tersimpan dan memperkirakan bahwa hanya sekitar 1000 di antaranya yang digunakan secara teratur, dan sekitar 200 lainnya digunakan pada kesempatan langka, artinya kami memiliki banyak pekerjaan yang harus dilakukan.

Karena kami memiliki banyak departemen dan tim yang dapat mengakses database dan prosedur ini, kami tidak selalu yang memanggil prosedur, artinya kami harus menentukan prosedur apa yang dipanggil. Selain itu, kami ingin menentukan ini selama beberapa bulan, bukan dalam beberapa hari (yang menghilangkan beberapa kemungkinan).

Salah satu pendekatan untuk ini adalah dengan menggunakan SQL Server Profilerdan melacak prosedur apa yang dipanggil dan membandingkannya dengan daftar prosedur apa yang kita miliki, sambil menandai apakah prosedur tersebut digunakan atau tidak. Sejak saat itu, kami dapat memindahkan prosedur ke skema lain jika suatu departemen berteriak.

Apakah menggunakan pendekatan Profileryang paling efektif di sini? Dan / Atau pernahkah Anda melakukan sesuatu yang serupa dan menemukan cara lain / cara yang lebih baik untuk melakukan ini?

Pertanyaan3CPO
sumber

Jawaban:

32

Anda dapat menggunakan penelusuran sisi server (berbeda dengan menggunakan GUI Profiler yang menimbulkan lebih banyak sumber daya) selama pengujian atau siklus bisnis Anda dan hanya menangkap hal-hal yang terkait dengan SP. Kemudian Anda bisa memuatnya dalam tabel atau unggul untuk analisis lebih lanjut.

Pendekatan kedua, adalah menggunakan DMV sys.dm_exec_procedure_stats (dengan batasan bahwa jika sql server di-restart, maka datanya memerah).

Anda bahkan dapat menjadwalkan pekerjaan untuk mengambil data DMV ke tabel agar tetap ada.

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

Mengacu pada :

Kin Shah
sumber
1
Juga lihat stackoverflow.com/questions/10421439/... dan stackoverflow.com/questions/7150900/… (mengabaikan bahwa pada yang terakhir tautan ke SQLServerPedia sekarang mati).
Aaron Bertrand
2
Pastikan Anda memeriksa DMV secara berkala selama berminggu-minggu atau bahkan berbulan-bulan karena mungkin ada SP yang hanya dijalankan secara bulanan atau bahkan triwulanan. DMV dihapus ketika instance dihidupkan ulang, dihapus secara manual, atau bahkan hanya seiring waktu.
Kenneth Fisher
1
@KennethFisher Itulah mengapa saya merekomendasikan untuk menjadwalkan pekerjaan untuk mengambil data DMV ke tabel. Terima kasih telah menyebutkan!
Kin Shah
11

Anda dapat menemukan pertanyaan ini berguna, ini berlaku untuk tabel dan kolom tetapi menyarankan menggunakan alat pihak ketiga ApexSQL Clean yang juga dapat menemukan prosedur tersimpan yang tidak digunakan serta semua objek yang tidak direferensikan oleh objek lain dalam database, atau dalam database eksternal

Penafian: Saya bekerja untuk ApexSQL sebagai Support Engineer

Milica Medic
sumber
3
OP tidak ingin menemukan unreferenced stored procedures, sebaliknya OP ingin menemukan SP yang tidak digunakan. Jawaban Anda tidak berfungsi sebagai jawaban untuk pertanyaan ini.
Kin Shah
Kin saya akan memperbarui. ApexSQL Clean menandai objek yang tidak digunakan sebagai tidak direferensikan jadi saya mengerti bahwa itu yang menyebabkan kebingungan
Milica Medic
10

Jika Anda menggunakan SQL Server 2008+, Anda juga dapat menggunakan acara yang diperluas dengan target histogram . Mungkin ini akan lebih ringan daripada jejak.

AFAIK Anda perlu membuat sesi yang berbeda untuk setiap basis data yang menarik karena saya tidak dapat melihat indikasi bahwa penataan pada beberapa kolom dimungkinkan. Contoh cepat di bawah ini menyaringdatabase_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

Dan kemudian setelah menjalankan beberapa prosedur tersimpan di DB itu beberapa kali dan mengambil data dengan

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'

Outputnya adalah

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

Menunjukkan bahwa prosedur dengan object_iddari 1287675635dieksekusi 36 kali misalnya. Hanya asynchronous_bucketizermemori, jadi yang terbaik adalah mengatur sesuatu yang polling ini sering dan menyimpan ke penyimpanan persisten.

Martin Smith
sumber
1
Memang benar, Anda perlu satu sesi per basis data. Akan bagus untuk mengatakan WHERE (source_database_id IN (10,15,20))tetapi sayangnya ini tidak didukung.
Aaron Bertrand
@ AaronBertrand - Dan bahkan jika didukung, Anda masih perlu menghitung panggilan prosedur untuk objek dengan yang sama object_id(atau sama object_name) dalam database yang berbeda secara terpisah dan saya tidak berpikir itu mungkin juga.
Martin Smith
Benar saya jika saya salah tetapi di extended eventsmana ditambahkan pada 2012 bukan 2008?
Peter
1
@ Peter ya kamu salah. :-) technet.microsoft.com/en-us/library/dd822788(v=sql.100).aspx
Martin Smith
1
Acara diperpanjang UI tidak diperkenalkan sampai SSMS 2012 dan saya tidak berpikir mereka membuatnya kompatibel. Pada 2008 satu-satunya cara untuk membuat sesi di luar kotak adalah melalui TSQL meskipun ada proyek komunitas untuk fungsionalitas serupa extendedeventmanager.codeplex.com
Martin Smith
4

Sebagai tindak lanjut dari naskah Kin. Berikut ini adalah skrip sederhana untuk membuat tabel untuk melacak penggunaan dari waktu ke waktu & skrip untuk memperbaruinya secara berkala.

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

Posting ini juga menyediakan skrip untuk menemukan oject yang tidak digunakan: Cari tabel database yang tidak digunakan di SQL Server Di bawah ini adalah skrip dari artikel, saya mengubah tipe tabel "U" menjadi tipe prosedur tersimpan "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
Milica Medic
sumber
Ini akan selalu mengembalikan semua prosedur karena prosedur tidak mendapatkan entri yang dibuat dalam statistik penggunaan indeks DMV ...
Martin Smith