Làm thế nào để có được việc sử dụng CPU theo cơ sở dữ liệu cụ thể?


15

Tôi đã tìm thấy các truy vấn sau đây để phát hiện việc sử dụng CPU theo cơ sở dữ liệu, nhưng chúng đang hiển thị các kết quả khác nhau:

WITH DB_CPU_Stats
AS
(
    SELECT DatabaseID, DB_Name(DatabaseID) AS [DatabaseName], 
      SUM(total_worker_time) AS [CPU_Time_Ms]
    FROM sys.dm_exec_query_stats AS qs
    CROSS APPLY (
                    SELECT CONVERT(int, value) AS [DatabaseID] 
                  FROM sys.dm_exec_plan_attributes(qs.plan_handle)
                  WHERE attribute = N'dbid') AS F_DB
    GROUP BY DatabaseID
)
SELECT ROW_NUMBER() OVER(ORDER BY [CPU_Time_Ms] DESC) AS [row_num],
       DatabaseName,
        [CPU_Time_Ms], 
       CAST([CPU_Time_Ms] * 1.0 / SUM([CPU_Time_Ms]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [CPUPercent]
FROM DB_CPU_Stats
--WHERE DatabaseID > 4 -- system databases
--AND DatabaseID <> 32767 -- ResourceDB
ORDER BY row_num OPTION (RECOMPILE);

Truy vấn trên cho biết rằng sự cố xảy ra với một trong các cơ sở dữ liệu của tôi (gần 96%).

Và truy vấn bên dưới cho biết rằng sự cố xảy ra với cơ sở dữ liệu chính và cơ sở phân phối (khoảng 90%):

DECLARE @total INT
SELECT @total=sum(cpu) FROM sys.sysprocesses sp (NOLOCK)
    join sys.sysdatabases sb (NOLOCK) ON sp.dbid = sb.dbid

SELECT sb.name 'database', @total 'system cpu', SUM(cpu) 'database cpu', CONVERT(DECIMAL(4,1), CONVERT(DECIMAL(17,2),SUM(cpu)) / CONVERT(DECIMAL(17,2),@total)*100) '%'
FROM sys.sysprocesses sp (NOLOCK)
JOIN sys.sysdatabases sb (NOLOCK) ON sp.dbid = sb.dbid
--WHERE sp.status = 'runnable'
GROUP BY sb.name
ORDER BY CONVERT(DECIMAL(4,1), CONVERT(DECIMAL(17,2),SUM(cpu)) / CONVERT(DECIMAL(17,2),@total)*100) desc

Tôi đã kiểm tra xem đó sys.sysprocesseslà giải pháp. Điều này có nghĩa là kết quả từ truy vấn thứ hai là sai?

Câu trả lời:


14

Trong khi tôi, như @Thomas, hoàn toàn đồng ý với @Aaron trong các nhận xét về câu hỏi liên quan đến mối quan tâm về "sử dụng CPU trên cơ sở dữ liệu" là chính xác hay hữu ích, ít nhất tôi có thể trả lời câu hỏi tại sao hai truy vấn đó lại như vậy khác nhau. Và lý do tại sao chúng khác nhau sẽ chỉ ra cái nào chính xác hơn, mặc dù mức độ chính xác cao hơn vẫn tương đối với cái không chính xác, do đó vẫn không thực sự chính xác ;-).

Truy vấn đầu tiên sử dụng sys.dm_exec_query_stats để lấy thông tin CPU (tức là total_worker_time). Nếu bạn đi đến trang được liên kết là tài liệu MSDN cho DMV đó, bạn sẽ thấy một đoạn giới thiệu ngắn, 3 câu và 2 trong số những câu đó cho chúng ta hầu hết những gì chúng ta cần để hiểu ngữ cảnh của thông tin này ("nó đáng tin cậy đến mức nào" và "làm thế nào để nó so sánh với sys.sysprocesses"). Hai câu đó là:

Trả về thống kê hiệu suất tổng hợp cho các gói truy vấn được lưu trong bộ đệm SQL Server. ... Khi một gói được xóa khỏi bộ đệm, các hàng tương ứng sẽ bị loại khỏi chế độ xem này

Câu đầu tiên, "Trả về thống kê hiệu suất tổng hợp ", cho chúng tôi biết rằng thông tin trong DMV này (giống như một số thông tin khác) được tích lũy và không cụ thể cho chỉ các truy vấn hiện đang chạy. Điều này cũng được chỉ định bởi một trường trong DMV không phải là một phần của truy vấn trong Câu hỏi, execution_countmột lần nữa cho thấy đây là dữ liệu tích lũy. Và nó khá thuận tiện để dữ liệu này được tích lũy khi bạn có thể lấy trung bình, v.v. bằng cách chia một số số liệu cho execution_count.

Câu thứ hai, "các kế hoạch bị xóa khỏi bộ đệm cũng bị xóa khỏi DMV này", chỉ ra rằng đó hoàn toàn không phải là một bức tranh hoàn chỉnh, đặc biệt là nếu máy chủ đã có bộ đệm kế hoạch khá đầy đủ và đang được tải và do đó hết hạn hơi thường xuyên Ngoài ra, hầu hết các DMV được đặt lại khi máy chủ đặt lại để chúng không phải là lịch sử thực sự ngay cả khi các hàng này không bị xóa khi hết hạn gói.

Bây giờ hãy tương phản ở trên với sys.sysprocesses. Chế độ xem hệ thống này chỉ hiển thị những gì hiện đang chạy, giống như sự kết hợp của sys.dm_exec_connections , sys.dm_exec_smentssys.dm_exec numquests (được nêu trên trang được liên kết cho sys.dm_exec_sessions). Đây là một cái nhìn hoàn toàn khác về máy chủ so vớisys.dm_exec_query_stats DMV giữ dữ liệu ngay cả khi quá trình hoàn tất. Có nghĩa là, liên quan đến "kết quả từ truy vấn thứ hai có sai không?" câu hỏi, họ không sai, họ chỉ liên quan đến một khía cạnh khác (tức là khung thời gian) của các số liệu thống kê hiệu suất.

Vì vậy, truy vấn sử dụng sys.sysprocesseschỉ nhìn vào "ngay bây giờ". Và truy vấn sử dụng sys.dm_exec_query_statsđang xem xét hầu hết (có thể) những gì đã xảy ra kể từ lần khởi động lại cuối cùng của dịch vụ SQL Server (hoặc rõ ràng là khởi động lại hệ thống). Đối với phân tích hiệu suất chung có vẻ như sys.dm_exec_query_statstốt hơn nhiều, nhưng một lần nữa, nó giảm thông tin hữu ích mọi lúc. Và, trong cả hai trường hợp, bạn cũng cần xem xét các điểm được tạo bởi @Aaron trong các nhận xét câu hỏi (đã bị xóa) về độ chính xác của giá trị "cơ sở dữ liệu" ở vị trí đầu tiên (nghĩa là nó chỉ phản ánh DB hoạt động đã khởi tạo mã , không nhất thiết là nơi "vấn đề" đang xảy ra).

Tuy nhiên, nếu bạn chỉ cần / muốn có được một cảm giác về những gì đang xảy ra ngay bây giờ trên tất cả các cơ sở dữ liệu, có thể vì những thứ đang chậm lại ngay bây giờ, bạn nên sử dụng sự kết hợp của sys.dm_exec_connections, sys.dm_exec_sessionssys.dm_exec_requests(và không phải là bị phản đối sys.sysprocesses). Chỉ cần lưu ý rằng bạn đang xem / tìm kiếm truy vấn , không phải cơ sở dữ liệu , bởi vì các truy vấn có thể tham gia trên nhiều cơ sở dữ liệu, bao gồm UDF từ một hoặc nhiều cơ sở dữ liệu, v.v.


EDIT:
Nếu mối quan tâm chung là làm giảm người tiêu dùng CPU cao, thì hãy tìm các truy vấn chiếm nhiều CPU nhất, vì cơ sở dữ liệu không thực sự chiếm CPU (tìm kiếm trên mỗi cơ sở dữ liệu có thể hoạt động tại một công ty lưu trữ, nơi mỗi cơ sở dữ liệu được cách ly và thuộc sở hữu của một khách hàng khác nhau).

Truy vấn sau đây sẽ giúp xác định các truy vấn có mức sử dụng CPU trung bình cao. Nó ngưng tụ dữ liệu trong query_stats DMV vì các bản ghi đó có thể hiển thị cùng một truy vấn (có, cùng một tập hợp con của lô truy vấn) nhiều lần, mỗi lần có một kế hoạch thực hiện khác nhau.

;WITH cte AS
(
  SELECT stat.[sql_handle],
         stat.statement_start_offset,
         stat.statement_end_offset,
         COUNT(*) AS [NumExecutionPlans],
         SUM(stat.execution_count) AS [TotalExecutions],
         ((SUM(stat.total_logical_reads) * 1.0) / SUM(stat.execution_count)) AS [AvgLogicalReads],
         ((SUM(stat.total_worker_time) * 1.0) / SUM(stat.execution_count)) AS [AvgCPU]
  FROM sys.dm_exec_query_stats stat
  GROUP BY stat.[sql_handle], stat.statement_start_offset, stat.statement_end_offset
)
SELECT CONVERT(DECIMAL(15, 5), cte.AvgCPU) AS [AvgCPU],
       CONVERT(DECIMAL(15, 5), cte.AvgLogicalReads) AS [AvgLogicalReads],
       cte.NumExecutionPlans,
       cte.TotalExecutions,
       DB_NAME(txt.[dbid]) AS [DatabaseName],
       OBJECT_NAME(txt.objectid, txt.[dbid]) AS [ObjectName],
       SUBSTRING(txt.[text], (cte.statement_start_offset / 2) + 1,
       (
         (CASE cte.statement_end_offset 
           WHEN -1 THEN DATALENGTH(txt.[text])
           ELSE cte.statement_end_offset
          END - cte.statement_start_offset) / 2
         ) + 1
       )
FROM cte
CROSS APPLY sys.dm_exec_sql_text(cte.[sql_handle]) txt
ORDER BY cte.AvgCPU DESC;

tính AvgCPUbằng mili giây?
Hẻm núi Kolob

Xin chào @KolobCanyon. Theo tài liệu cho sys.dm_exec_query_stats , total_worker_timelà " Tổng thời lượng CPU, được báo cáo tính bằng micro giây (nhưng chỉ chính xác đến mili giây), được sử dụng bởi việc thực thi kế hoạch này kể từ khi nó được biên dịch. ". cái đó có giúp ích không? Điều đó có thể dễ dàng được chuyển đổi thành mili giây nếu đó là những gì bạn muốn xem nó như.
Solomon Rutzky

1

Tôi đã điều chỉnh truy vấn để chia cho 0 lỗi và tối ưu hóa tên cột để sao chép / dán vào Excel.

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
GO
WITH DB_CPU_Stats
AS
(
    SELECT DatabaseID, isnull(DB_Name(DatabaseID),case DatabaseID when 32767 then 'Internal ResourceDB' else CONVERT(varchar(255),DatabaseID)end) AS [DatabaseName], 
      SUM(total_worker_time) AS [CPU_Time_Ms],
      SUM(total_logical_reads)  AS [Logical_Reads],
      SUM(total_logical_writes)  AS [Logical_Writes],
      SUM(total_logical_reads+total_logical_writes)  AS [Logical_IO],
      SUM(total_physical_reads)  AS [Physical_Reads],
      SUM(total_elapsed_time)  AS [Duration_MicroSec],
      SUM(total_clr_time)  AS [CLR_Time_MicroSec],
      SUM(total_rows)  AS [Rows_Returned],
      SUM(execution_count)  AS [Execution_Count],
      count(*) 'Plan_Count'
    FROM sys.dm_exec_query_stats AS qs
    CROSS APPLY (
                    SELECT CONVERT(int, value) AS [DatabaseID] 
                  FROM sys.dm_exec_plan_attributes(qs.plan_handle)
                  WHERE attribute = N'dbid') AS F_DB
    GROUP BY DatabaseID
)
SELECT ROW_NUMBER() OVER(ORDER BY [CPU_Time_Ms] DESC) AS [Rank_CPU],
       DatabaseName,
       [CPU_Time_Hr] = convert(decimal(15,2),([CPU_Time_Ms]/1000.0)/3600) ,
        CAST([CPU_Time_Ms] * 1.0 / SUM(case [CPU_Time_Ms] when 0 then 1 else [CPU_Time_Ms] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [CPU_Percent],
       [Duration_Hr] = convert(decimal(15,2),([Duration_MicroSec]/1000000.0)/3600) , 
       CAST([Duration_MicroSec] * 1.0 / SUM(case [Duration_MicroSec] when 0 then 1 else [Duration_MicroSec] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Duration_Percent],    
       [Logical_Reads],
        CAST([Logical_Reads] * 1.0 / SUM(case [Logical_Reads] when 0 then 1 else [Logical_Reads] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Logical_Reads_Percent],      
       [Rows_Returned],
        CAST([Rows_Returned] * 1.0 / SUM(case [Rows_Returned] when 0 then 1 else [Rows_Returned] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Rows_Returned_Percent],
       [Reads_Per_Row_Returned] = [Logical_Reads]/(case [Rows_Returned] when 0 then 1 else [Rows_Returned] end),
       [Execution_Count],
        CAST([Execution_Count] * 1.0 / SUM(case [Execution_Count]  when 0 then 1 else [Execution_Count] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Execution_Count_Percent],
       [Physical_Reads],
       CAST([Physical_Reads] * 1.0 / SUM(case [Physical_Reads] when 0 then 1 else [Physical_Reads] end ) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Physcal_Reads_Percent], 
       [Logical_Writes],
        CAST([Logical_Writes] * 1.0 / SUM(case [Logical_Writes] when 0 then 1 else [Logical_Writes] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Logical_Writes_Percent],
       [Logical_IO],
        CAST([Logical_IO] * 1.0 / SUM(case [Logical_IO] when 0 then 1 else [Logical_IO] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Logical_IO_Percent],
       [CLR_Time_MicroSec],
       CAST([CLR_Time_MicroSec] * 1.0 / SUM(case [CLR_Time_MicroSec] when 0 then 1 else [CLR_Time_MicroSec] end ) OVER() * 100.0 AS DECIMAL(5, 2)) AS [CLR_Time_Percent],
       [CPU_Time_Ms],[CPU_Time_Ms]/1000 [CPU_Time_Sec],
       [Duration_MicroSec],[Duration_MicroSec]/1000000 [Duration_Sec]
FROM DB_CPU_Stats
WHERE DatabaseID > 4 -- system databases
AND DatabaseID <> 32767 -- ResourceDB
ORDER BY [Rank_CPU] OPTION (RECOMPILE);

0

Tôi thích truy vấn CPU từ sys.dm_exec_query_statsrất nhiều mà tôi đã mở rộng nó. Nó vẫn được xếp hạng bởi CPU nhưng tôi đã thêm các tổng và phần trăm khác để có được cấu hình máy chủ tốt hơn. Điều này sao chép độc đáo vào Excel và với định dạng màu có điều kiện trên các cột Phần trăm, những con số tồi tệ nhất nổi bật độc đáo. Tôi đã sử dụng 'Thang màu được phân loại' với 3 màu; một màu hoa hồng cho giá trị cao, màu vàng cho giữa, màu xanh lá cây cho thấp.

Tôi đã thêm một Nhãn cho database id 32676Cơ sở dữ liệu tài nguyên SQL nội bộ. Tôi chuyển đổi CPU và Thời lượng thời gian thành Giờ để hiểu rõ hơn về việc sử dụng thời gian.

WITH DB_CPU_Stats
AS
(
    SELECT DatabaseID, isnull(DB_Name(DatabaseID),case DatabaseID when 32767 then 'Internal ResourceDB' else CONVERT(varchar(255),DatabaseID)end) AS [DatabaseName], 
      SUM(total_worker_time) AS [CPU Time Ms],
      SUM(total_logical_reads)  AS [Logical Reads],
      SUM(total_logical_writes)  AS [Logical Writes],
      SUM(total_logical_reads+total_logical_writes)  AS [Logical IO],
      SUM(total_physical_reads)  AS [Physical Reads],
      SUM(total_elapsed_time)  AS [Duration MicroSec],
      SUM(total_clr_time)  AS [CLR Time MicroSec],
      SUM(total_rows)  AS [Rows Returned],
      SUM(execution_count)  AS [Execution Count],
      count(*) 'Plan Count'

    FROM sys.dm_exec_query_stats AS qs
    CROSS APPLY (
                    SELECT CONVERT(int, value) AS [DatabaseID] 
                  FROM sys.dm_exec_plan_attributes(qs.plan_handle)
                  WHERE attribute = N'dbid') AS F_DB
    GROUP BY DatabaseID
)
SELECT ROW_NUMBER() OVER(ORDER BY [CPU Time Ms] DESC) AS [Rank CPU],
       DatabaseName,
       [CPU Time Hr] = convert(decimal(15,2),([CPU Time Ms]/1000.0)/3600) ,
        CAST([CPU Time Ms] * 1.0 / SUM([CPU Time Ms]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [CPU Percent],
       [Duration Hr] = convert(decimal(15,2),([Duration MicroSec]/1000000.0)/3600) , 
       CAST([Duration MicroSec] * 1.0 / SUM([Duration MicroSec]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Duration Percent],    
       [Logical Reads],
        CAST([Logical Reads] * 1.0 / SUM([Logical Reads]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Logical Reads Percent],      
       [Rows Returned],
        CAST([Rows Returned] * 1.0 / SUM([Rows Returned]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Rows Returned Percent],
       [Reads Per Row Returned] = [Logical Reads]/[Rows Returned],
       [Execution Count],
        CAST([Execution Count] * 1.0 / SUM([Execution Count]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Execution Count Percent],
       [Physical Reads],
       CAST([Physical Reads] * 1.0 / SUM([Physical Reads]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Physcal Reads Percent], 
       [Logical Writes],
        CAST([Logical Writes] * 1.0 / SUM([Logical Writes]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Logical Writes Percent],
       [Logical IO],
        CAST([Logical IO] * 1.0 / SUM([Logical IO]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Logical IO Percent],
       [CLR Time MicroSec],
       CAST([CLR Time MicroSec] * 1.0 / SUM(case [CLR Time MicroSec] when 0 then 1 else [CLR Time MicroSec] end ) OVER() * 100.0 AS DECIMAL(5, 2)) AS [CLR Time Percent],
       [CPU Time Ms],[CPU Time Ms]/1000 [CPU Time Sec],
       [Duration MicroSec],[Duration MicroSec]/1000000 [Duration Sec]
FROM DB_CPU_Stats
--WHERE DatabaseID > 4 -- system databases
--AND DatabaseID <> 32767 -- ResourceDB
ORDER BY [Rank CPU] OPTION (RECOMPILE);
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.