ระบุขั้นตอนการจัดเก็บที่ไม่ได้ใช้


24

ในปีหน้านี้ฉันกำลังช่วยทำความสะอาดสภาพแวดล้อม SQL Server หลายแห่ง

เรามีขั้นตอนการจัดเก็บประมาณ 10,000 รายการและประมาณว่ามีเพียง 1,000 รายการเท่านั้นที่ใช้เป็นประจำและอีก 200 รายการจะใช้ในโอกาสที่หายากซึ่งหมายความว่าเรามีงานต้องทำมากมาย

เนื่องจากเรามีหลายแผนกและทีมที่สามารถเข้าถึงฐานข้อมูลและขั้นตอนเหล่านี้ได้เราจึงไม่ใช่คนที่เรียกขั้นตอนเหล่านี้เสมอไปซึ่งหมายความว่าเราต้องกำหนดว่าจะเรียกใช้ขั้นตอนใด ยิ่งไปกว่านั้นเราต้องการตรวจสอบสิ่งนี้ในอีกไม่กี่เดือนไม่ใช่ในอีกสองสามวัน (ซึ่งเป็นการขจัดความเป็นไปได้บางอย่าง)

วิธีการหนึ่งในการทำเช่นนี้คือการใช้SQL Server Profilerและติดตามว่ากระบวนการใดที่ถูกเรียกใช้และเปรียบเทียบกับรายการของกระบวนการที่เรามีในขณะที่ทำเครื่องหมายว่ามีการใช้งานหรือไม่ จากนั้นเราสามารถย้ายขั้นตอนไปยังสคีมาอื่นในกรณีที่แผนกกรีดร้อง

ใช้Profilerวิธีที่มีประสิทธิภาพที่สุดที่นี่หรือไม่? และ / หรือคุณเคยทำสิ่งที่คล้ายกันและพบวิธีอื่น / วิธีที่ดีกว่าในการทำเช่นนี้?

คำตอบ:


32

คุณสามารถใช้การติดตามฝั่งเซิร์ฟเวอร์ (แตกต่างจากการใช้ Profiler GUI ที่ก่อให้เกิดทรัพยากรมากขึ้น) ในระหว่างการทดสอบหรือวัฏจักรธุรกิจของคุณและบันทึกเฉพาะสิ่งที่เกี่ยวข้องกับ SP จากนั้นคุณสามารถโหลดในตารางหรือ excel สำหรับการวิเคราะห์เพิ่มเติม

วิธีที่สองคือการใช้ 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 จะตายแล้ว)
Aaron Bertrand

2
ตรวจสอบให้แน่ใจว่าคุณตรวจสอบ DMV เป็นระยะในช่วงสัปดาห์หรือเป็นเดือนเนื่องจากอาจมี SP ที่ทำงานเฉพาะรายเดือนหรือรายไตรมาส DMV จะถูกล้างออกเมื่อมีการรีสตาร์ทอินสแตนซ์ล้างด้วยตนเองหรือแม้กระทั่งเมื่อเวลาผ่านไป
Kenneth Fisher

1
@ KennethFisher นั่นเป็นสาเหตุที่ฉันแนะนำให้จัดตารางงานเพื่อเก็บข้อมูล DMV ไปยังตาราง ขอบคุณที่กล่าวถึง!
Kin Shah

11

คุณสามารถค้นหาคำถามนี้มีประโยชน์ใช้กับตารางและคอลัมน์ แต่แนะนำให้ใช้เครื่องมือของบุคคลที่สาม ApexSQL Clean ซึ่งสามารถค้นหากระบวนงานที่เก็บไว้ที่ไม่ได้ใช้รวมถึงวัตถุทั้งหมดที่ไม่ได้อ้างอิงโดยวัตถุอื่นใดในฐานข้อมูลหรือในฐานข้อมูลภายนอก

คำเตือน: ฉันทำงานให้กับ ApexSQL ในฐานะวิศวกรสนับสนุน


3
OP ไม่ต้องการค้นหาunreferenced stored proceduresแต่ OP ต้องการค้นหา SP ที่ไม่ได้ใช้ คำตอบของคุณไม่ได้เป็นคำตอบสำหรับคำถามนี้
Kin Shah

Kin ฉันจะอัปเดต ApexSQL Clean ทำเครื่องหมายวัตถุที่ไม่ได้ใช้เป็น unreferenced ดังนั้นฉันเข้าใจว่าทำให้เกิดความสับสน
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))แต่อนิจจานี้ไม่ได้รับการสนับสนุน
Aaron Bertrand

@AaronBertrand - และถึงแม้ว่ามันจะได้รับการสนับสนุนคุณก็ยังต้องนับการเรียกโพรซีเดอร์สำหรับออบเจกต์ที่เหมือนกันobject_id(หรือเหมือนกันobject_name) ในฐานข้อมูลต่าง ๆ แยกกันและฉันก็ไม่คิดว่ามันจะเป็นไปได้เช่นกัน
Martin Smith

ถูกต้องฉันถ้าฉันผิด แต่extended eventsที่เพิ่มในปี 2012 ไม่ใช่ปี 2008?
ปีเตอร์

1
@ ปีเตอร์คุณเข้าใจผิด :-) technet.microsoft.com/en-us/library/dd822788(v=sql.100).aspx
Martin Smith

1
UI กิจกรรมเพิ่มเติมไม่ได้ถูกนำมาใช้จนกว่า SSMS 2012 และฉันไม่คิดว่ามันจะเข้ากันได้ย้อนหลัง 2008 วิธีเดียวที่จะสร้างเซสชันจากกล่องก็ผ่าน TSQL แม้ว่าจะมีโครงการชุมชนเพื่อการทำงานที่คล้ายกันextendedeventmanager.codeplex.com
มาร์ตินสมิ ธ

4

เป็นไปตามสคริปต์ของ Kin นี่คือสคริปต์ง่ายๆในการสร้างตารางเพื่อติดตามการใช้งานเมื่อเวลาผ่านไป & สคริปต์เพื่ออัปเดตเป็นระยะ

--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--  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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.