Xác định các thủ tục lưu trữ không sử dụng


24

Năm tới, tôi sẽ giúp nỗ lực dọn dẹp một số môi trường Máy chủ SQL.

Chúng tôi có khoảng 10.000 thủ tục được lưu trữ và ước tính rằng chỉ có khoảng 1000 trong số chúng được sử dụng một cách thường xuyên và 200 hoặc hơn nữa được sử dụng trong một dịp hiếm hoi, có nghĩa là chúng tôi có rất nhiều việc phải làm.

Vì chúng tôi có nhiều phòng ban và nhóm có thể truy cập các cơ sở dữ liệu và quy trình này, chúng tôi không phải lúc nào cũng là những người gọi thủ tục, nghĩa là chúng tôi phải xác định thủ tục nào đang được gọi. Trên hết, chúng tôi muốn xác định điều này trong một vài tháng, không phải trong một vài ngày (loại bỏ một số khả năng).

Một cách tiếp cận này là sử dụng SQL Server Profilervà theo dõi những thủ tục nào đang được gọi và so sánh chúng với danh sách những thủ tục chúng ta có, đồng thời đánh dấu xem các thủ tục có được sử dụng hay không. Từ đó, chúng ta có thể chuyển các thủ tục sang một lược đồ khác trong trường hợp một bộ phận đến la hét.

Là sử dụng Profilerphương pháp hiệu quả nhất ở đây? Và / Hoặc có ai trong số các bạn đã làm điều gì đó tương tự và tìm thấy một cách khác / cách tốt hơn để làm điều này?

Câu trả lời:


32

Bạn có thể sử dụng theo dõi phía máy chủ (khác với sử dụng GUI Profiler phát sinh thêm tài nguyên) trong quá trình thử nghiệm hoặc chu kỳ kinh doanh của bạn và chỉ thu thập những thứ liên quan đến SP. Sau đó, bạn có thể tải nó trong một bảng hoặc excel để phân tích thêm.

Cách tiếp cận thứ hai, là sử dụng DMV sys.dm_exec_procedure_stats (với giới hạn là nếu máy chủ sql được khởi động lại, thì dữ liệu sẽ bị xóa).

Bạn thậm chí có thể lên lịch công việc để thu thập dữ liệu DMV vào một bảng để duy trì nó.

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

Tham khảo:


1
Đồng thời xem stackoverflow.com/questions/10421439/ và và stackoverflow.com/questions/7150900/ mẹo (bỏ qua điều đó ở phần sau, liên kết đến SQLServerPedia hiện đã chết).
Aaron Bertrand

2
Hãy chắc chắn rằng bạn kiểm tra DMV định kỳ trong vài tuần hoặc thậm chí vài tháng vì có thể có các SP chỉ được chạy trên cơ sở hàng tháng hoặc thậm chí hàng quý. DMV bị xóa khi cá thể được khởi động lại, xóa thủ công hoặc thậm chí chỉ theo thời gian.
Kenneth Fisher

1
@KennethFisher Đó là lý do tại sao tôi khuyên bạn nên lên lịch công việc để thu thập dữ liệu DMV vào bảng. Cảm ơn đã đề cập mặc dù!
Kin Shah

11

Bạn có thể thấy câu hỏi này hữu ích, nó áp dụng cho các bảng và cột nhưng đề xuất sử dụng công cụ ApexQuery Clean của bên thứ ba cũng có thể tìm thấy các thủ tục được lưu trữ không sử dụng cũng như tất cả các đối tượng không được tham chiếu bởi bất kỳ đối tượng nào khác trong cơ sở dữ liệu hoặc trong cơ sở dữ liệu bên ngoài

Tuyên bố miễn trừ trách nhiệm: Tôi làm việc cho ApexSQL với tư cách là Kỹ sư hỗ trợ


3
OP không muốn tìm unreferenced stored procedures, thay vào đó OP muốn tìm SP không sử dụng. Câu trả lời của bạn không phục vụ như một câu trả lời cho câu hỏi này.
Kin Shah

Kin tôi sẽ cập nhật. ApexSQL Clean đánh dấu các đối tượng không được sử dụng là không được ước tính vì vậy tôi hiểu rằng điều đó đã gây ra sự nhầm lẫn
Milica Medic

10

Nếu bạn đang sử dụng SQL Server 2008+, bạn cũng có thể sử dụng các sự kiện mở rộng với mục tiêu biểu đồ . Có thể đây sẽ là trọng lượng nhẹ hơn một dấu vết.

AFAIK bạn sẽ cần tạo một phiên khác nhau cho mỗi cơ sở dữ liệu quan tâm mặc dù tôi không thể thấy bất kỳ dấu hiệu nào cho thấy việc đóng thùng trên nhiều cột là có thể. Ví dụ nhanh bên dưới bộ lọc trêndatabase_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

Và sau khi chạy một số thủ tục được lưu trữ trong DB đó một vài lần và lấy dữ liệu bằng

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'

Đầu ra là

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

Hiển thị rằng thủ tục với object_idcác 1287675635được thực hiện 36 lần chẳng hạn. Bộ asynchronous_bucketizernhớ chỉ là bộ nhớ, vì vậy tốt nhất nên thiết lập một cái gì đó thường xuyên thăm dò ý kiến ​​này và lưu vào bộ lưu trữ liên tục.


1
Đó là sự thật, bạn cần một phiên cho mỗi cơ sở dữ liệu. Sẽ là tuyệt vời để nói WHERE (source_database_id IN (10,15,20))nhưng than ôi điều này không được hỗ trợ.
Aaron Bertrand

@AaronBertrand - Và ngay cả khi được hỗ trợ, bạn vẫn cần phải đếm các cuộc gọi thủ tục cho các đối tượng có cùng object_id(hoặc giống nhau object_name) trong các cơ sở dữ liệu khác nhau và tôi cũng không nghĩ điều đó là có thể.
Martin Smith

Chỉnh sửa cho tôi nếu tôi sai nhưng extended eventsđược thêm vào năm 2012 chứ không phải năm 2008?
Peter


1
Giao diện người dùng mở rộng không được giới thiệu cho đến SSMS 2012 và tôi không nghĩ họ đã làm cho nó tương thích ngược. Vào năm 2008, cách duy nhất để tạo ra các phiên là thông qua TSQL mặc dù có một dự án cộng đồng cho chức năng tương tự Extendedeventmanager.codeplex.com
Martin Smith

4

Theo kịch bản của Kin. Đây là một tập lệnh đơn giản để tạo một bảng để theo dõi việc sử dụng theo thời gian & một tập lệnh để cập nhật nó theo định kỳ.

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

Bài đăng này cũng cung cấp một tập lệnh để tìm các từ chối không sử dụng: Tìm các bảng cơ sở dữ liệu không sử dụng trong SQL Server Dưới đây là tập lệnh từ bài viết, tôi đã thay đổi loại bảng "U" thành loại thủ tục được lưu trữ "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

Điều này sẽ luôn trả về tất cả các quy trình vì các quy trình không nhận được các mục được thực hiện trong chỉ số sử dụng chỉ mục DMV ...
Martin Smith
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.