Kullanılmayan Saklı Prosedürleri Belirleme


24

Bu yıl, birkaç SQL Server ortamını temizleme çabasına yardım ediyorum.

Yaklaşık 10.000 saklı yordamımız var ve bunların yalnızca 1000'inin düzenli olarak kullanıldığını ve başka bir 200'ün nadiren de kullanıldığını, yani yapmamız gereken çok işin olduğunu tahmin ediyoruz.

Bu veritabanlarına ve prosedürlerine erişebilen birden fazla departmanımız ve ekibimiz olduğundan, her zaman prosedürleri çağıranlar değiliz; bu, hangi prosedürlerin çağrıldığını belirlememiz gerektiği anlamına gelir. Bunun da ötesinde, bunu birkaç ay içinde değil, bazı olasılıkları ortadan kaldırarak) birkaç ay içinde belirlemek istiyoruz.

Buna bir yaklaşım SQL Server Profiler, prosedürlerin kullanılıp kullanılmadığını işaret ederken hangi prosedürlerin çağrıldığını kullanmak ve bunları hangi prosedürlerin listesiyle karşılaştırmaktır. O andan itibaren, bir departmanın çığlık atması durumunda prosedürleri farklı bir şemaya taşıyabiliriz.

ProfilerBuradaki en etkili yaklaşımı kullanmak mı ? Ve / veya herhangi biriniz benzer bir şey yaptı ve bunu yapmanın başka bir yolunu / daha iyi bir yolunu buldunuz mu?

Yanıtlar:


32

Sen kullanabilirsiniz sunucu tarafı izleme sizin test veya iş döngüsü ve yakalama sırasında yalnızca SP en ilişkili eşyalarını (gerçekleştikçe daha fazla kaynak olduğunu Profiler GUI kullanarak farklı). Sonra bunu bir tabloya yükleyebilir veya daha fazla analiz için excel.

İkinci yaklaşım, DMV sys.dm_exec_procedure_stats kullanmaktır (sql sunucusu yeniden başlatılırsa verinin boşaltılması ile sınırlandırılır).

DMV verilerini kalıcı tutmak için bir tabloya kaydetmek için bir iş bile planlayabilirsiniz.

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

Bakınız:


1
Ayrıca bkz. Stackoverflow.com/questions/10421439/… ve stackoverflow.com/questions/7150900/… (ikincisinde SQLServerPedia bağlantısının artık öldüğünü göz ardı ederek).
Aaron Bertrand

2
DMV'yi haftalar veya hatta aylar boyunca periyodik olarak kontrol ettiğinizden emin olun, zira sadece aylık veya üç ayda bir koşan SP'ler olabilir. DMV'ler, örnek yeniden başlatıldığında, manuel olarak temizlendiğinde veya hatta zaman içinde temizlenir.
Kenneth Fisher

1
@KennethFisher Bu yüzden DMV verilerini bir tabloya kaydedecek bir iş planladım. Yine de bahsettiğin için teşekkürler!
Kin Shah,

11

Bu soruyu faydalı bulabilirsiniz , tablolar ve sütunlar için geçerlidir, ancak kullanılmayan saklı yordamları ve ayrıca veritabanında veya harici veritabanlarında başka bir nesne tarafından referans alınmayan tüm nesneleri bulabilen üçüncü taraf bir araç ApexSQL Clean kullanılmasını önerir.

Yasal Uyarı: ApexSQL için Destek Mühendisi olarak çalışıyorum


3
OP bulmak istemiyor unreferenced stored procedures, bunun yerine OP kullanılmayan SP'yi bulmak istiyor. Cevabınız bu sorunun cevabı değil.
Kin Shah

Kin güncelleme yapacağım. ApexSQL Clean kullanılmayan nesneleri referans alınmadı olarak işaretler, bu yüzden karışıklığa neden olduğunu anlıyorum
Milica Medic

10

SQL Server 2008+ kullanıyorsanız, genişletilmiş olayları histogram hedefli olarak da kullanabilirsiniz . Muhtemelen bu bir izden daha hafif olacaktır.

AFAIK, her bir veritabanı için farklı bir oturum oluşturmanız gerekecektir, ancak birden fazla sütun üzerinde kovalamanın mümkün olduğuna dair herhangi bir belirti göremedim. Aşağıdaki filtrelere hızlı bir örnekdatabase_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

Ve sonra birkaç kez o DB'de bazı saklı yordamları çalıştırdıktan ve verileri topladıktan sonra

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'

Çıktı

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

İle prosedür olduğunu gösteren object_idbir 1287675635örnek olarak 36 kez idam edildi. Bu asynchronous_bucketizersadece hafızadır, bu yüzden bunu sık sık sorgulayan ve kalıcı depolamaya yol açan bir şeyler ayarlamak en iyisidir.


1
Doğru, veritabanı başına bir oturuma ihtiyacınız var. Söylemek harika olurdu WHERE (source_database_id IN (10,15,20))ama ne yazık ki bu desteklenmiyor.
Aaron Bertrand

@AaronBertrand - Desteklense bile, aynı veritabanını farklı veritabanlarında aynı object_id(veya aynı object_name) nesneler için ayrı ayrı yordamları saymaya ihtiyacınız olacak ve bunun da mümkün olduğunu sanmıyorum.
Martin Smith,

Yanlışysam düzeltin, ancak extended events2012’de 2008’de değil
Peter,


1
UI olayları, SSMS 2012'ye kadar sunulmadı ve geriye dönük olarak uyumlu yaptıklarını sanmıyorum. Benzer işlevsellik için bir topluluk projesi vardı gerçi 2008'de kutusundan dışarı oturumları oluşturmak için tek yol TSQL aracılığıyla oldu extendedeventmanager.codeplex.com
Martin Smith

4

Kin'in senaryosunun takipçisi olarak. İşte zaman içinde kullanımlarını izlemek için bir tablo oluşturmak için basit bir script ve periyodik olarak güncellemek için bir script.

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

Bu yazı aynı zamanda kullanılmayan nesneleri bulmak için bir komut dosyası sağlar: Kullanılmayan veritabanı tablolarını SQL Server'da bulma Aşağıdaki makaleden, "U" tablo tipini "P" depolanmış prosedür tipine değiştirdim:

   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

Bu, her zaman tüm prosedürleri döndürür, çünkü prosedürler endeks kullanım istatistiklerinde girişleri alamazlar DMV ...
Martin Smith
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.