特定のインスタンスのデータベースによるCPU使用率を取得する方法は?


15

データベースごとのCPU使用率を検出する次のクエリを見つけましたが、異なる結果が表示されています。

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

上記のクエリは、問題がデータベースの1つにあることを示しています(ほぼ96%)。

また、以下のクエリは、問題がマスターデータベースとディストリビューションデータベースにあることを示しています(約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

私はそれがチェックされていることを確認しましたsys.sysprocesses。これは、2番目のクエリの結果が間違っていることを意味していますか?

回答:


14

私は、@ Thomasのように、「データベースごとのCPU使用率」の正確性または有用性に関する懸念に関する質問のコメントで@Aaronに完全に同意しますが、少なくともこれら2つのクエリがそうである理由に関する質問には答えることができます違う。そして、それらが異なる理由は、どちらがより正確であるかを示しますが、その高いレベルの精度は、特に不正確なものと相対的であるため、まだ正確ではありません;-)。

最初のクエリはsys.dm_exec_query_statsを使用してCPU情報を取得します(例:)total_worker_time。そのDMVのMSDNドキュメントであるリンクされたページにアクセスすると、短い3文のイントロと2文がこの情報のコンテキストを理解するために必要なもののほとんどを提供します(「信頼性」)そして「それと比較してどうですかsys.sysprocesses」)。これらの2つの文は次のとおりです。

SQL Serverのキャッシュされたクエリプランの集計パフォーマンス統計を返します。...プランがキャッシュから削除されると、対応する行がこのビューから削除されます

最初の文「集計パフォーマンス統計を返す」は、このDMVの情報が(他のいくつかと同様に)累積的であり、現在実行中のクエリだけに固有のものではないことを示しています。これは、質問のクエリの一部ではないDMVのフィールドでも示されexecution_countます。これは、これが累積データであることを示しています。また、いくつかのメトリックをで除算することで平均などを取得できるため、このデータを累積しておくと非常に便利execution_countです。

2番目の文「キャッシュから削除されているプラ​​ンもこのDMVから削除されます」は、特にサーバーに既に十分なプランキャッシュがあり、負荷がかかっているためにプランが期限切れになる場合、完全な図ではないことを示していますやや頻繁に。また、ほとんどのDMVは、サーバーのリセット時にリセットされるため、プランの有効期限が切れたときにこれらの行が削除されなかった場合でも、真の履歴ではありません。

次に、上記とを対比してみましょうsys.sysprocesses。このシステムビューは、sys.dm_exec_connectionssys.dm_exec_sessions、およびsys.dm_exec_requests(のリンクページに記載されていますsys.dm_exec_sessions)の組み合わせのように、現在実行中のもののみを表示しています。これはsys.dm_exec_query_stats、プロセスの完了後もデータを保持するDMV と比較して、サーバーのまったく異なるビューです。「2番目のクエリの結果は間違っていますか?」質問、彼らは間違っていません、彼らは単にパフォーマンス統計の異​​なる側面(すなわち時間枠)に関係しています。

そのため、使用しているクエリsys.sysprocessesは「今」だけを見ています。また、使用しているクエリは、SQL Serverサービスの最後の再起動(または明らかにシステムの再起動)以降に起こったことを(おそらく)ほとんどsys.dm_exec_query_stats調べています。一般的なパフォーマンス分析では、はるかに優れているように見えますが、繰り返しますが、有用な情報は常に失われます。また、どちらの場合も、最初の場所の「database_id」値の正確性に関する質問コメント(削除されたため)で@Aaronが指摘した点を考慮する必要があります(つまり、コードを開始したアクティブなDBのみを反映します) 、「問題」が発生している場所とは限りません)。sys.dm_exec_query_stats

しかし、あなただけの必要性/物事が今鈍化している可能性があるため、あなたがの組み合わせを使用してオフに優れている、すべてのデータベース間で今何が起こっているかの感覚を取得したい場合はsys.dm_exec_connectionssys.dm_exec_sessions、及びsys.dm_exec_requests(および非推奨ではありませんsys.sysprocesses)。クエリは複数のデータベースに参加したり、1つまたは複数のデータベースからのUDFを含めたりすることができるため、データベースではなくクエリを探していることに注意してください。


編集:
全体的な懸念が高いCPU消費者を減らすことである場合、データベースが実際にCPUを占有しないため、CPUを最も消費しているクエリを探します(データベースごとに見ると、各データベースが分離されているホスティング会社で動作する可能性があります別の顧客が所有しています)。

次のクエリは、平均CPU使用率が高いクエリの特定に役立ちます。これらのレコードは同じクエリ(はい、クエリバッチの同じサブセット)を複数回、それぞれ異なる実行計画で表示できるため、query_stats DMVのデータを圧縮します。

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

AvgCPU、ミリ秒単位で?
コロブキャニオン

こんにちは@KolobCanyon。ドキュメントによるとsys.dm_exec_query_statstotal_worker_time「あるそれがコンパイルされたため、この計画の実行により消費されたマイクロ(しかし、ミリ秒だけ正確)で報告されたCPU時間の合計量は、。」。それは役立ちますか?それがあなたがそれを見たいと思うものであるならば、それは簡単にミリ秒に変換されることができました。
ソロモンラツキー

1

0除算エラーのクエリを調整し、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

CPUクエリがsys.dm_exec_query_stats非常に気に入ったため、拡張しました。CPUによってランク付けされていますが、より良いサーバープロファイルを得るために他の合計とパーセントを追加しました。これにより、Excelに適切にコピーされ、パーセント列に条件付きの色の書式が設定されているため、最悪の数値が目立ちます。3色の「グレーデッドカラースケール」を使用しました。高い値の場合はバラ色、中間の場合は黄色、低い値の場合は緑色。

database id 32676内部SQLリソースデータベースであるラベルを追加しました。CPUとDurationの時間をHoursに変換して、時間の使用状況をよりよく把握します。

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);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.