データベースごとの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番目のクエリの結果が間違っていることを意味しますか?
私は@Thomasと同様に、「データベースごとのCPU使用量」が正確または有用であるという懸念に関する質問のコメントで@Aaronに完全に同意しますが、少なくともこれら2つのクエリがなぜそうであるかについての質問に少なくとも答えることができます。違う。そして、それらが異なる理由は、どちらがより正確であるかを示しますが、より高いレベルの正確さは、具体的に不正確であるものと相対的であるため、まだ正確ではありません;-).
最初のクエリは sys.dm_exec_query_stats を使用してCPU情報を取得します(つまり、total_worker_time
)。そのDMVのMSDNドキュメントであるリンクされたページにアクセスすると、短い3つの文のイントロと2つの文が、この情報のコンテキストを理解するために必要なほとんどの情報を提供します(「どれほど信頼できるか」そして「それはsys.sysprocesses
と比較してどうですか」)。これらの2つの文は次のとおりです。
SQL Serverのキャッシュされたクエリプランの集計パフォーマンス統計を返します。 ...プランがキャッシュから削除されると、対応する行がこのビューから削除されます
最初の文「リターンaggregateパフォーマンス統計」は、このDMVの情報が(他のいくつかのように)累積的であり、現在実行中のクエリ。これは、質問のクエリの一部ではないそのDMVのフィールドexecution_count
によっても示されます。これも、これが累積データであることを示しています。また、一部のメトリックをexecution_count
で除算することで平均などを取得できるため、このデータを累積的に取得すると非常に便利です。
2番目の文「キャッシュから削除されているプランもこのDMVから削除されます」は、特にサーバーにかなり完全なプランキャッシュがあり、負荷がかかっているためプランが期限切れになる場合は、完全な全体像ではないことを示していますやや頻繁。また、ほとんどのDMVはサーバーのリセット時にリセットされるため、計画の有効期限が切れたときにこれらの行が削除されなかったとしても、それらは実際の履歴ではありません。
では、上記とsys.sysprocesses
を対比してみましょう。このシステムビューでは、 sys.dm_exec_connections 、 sys.dm_exec_sessions 、および sys.dm_exec_requests ( sys.dm_exec_sessions
)のリンク先ページに記載されています。これは、プロセスの完了後もデータを保持するsys.dm_exec_query_stats
DMVと比較すると、サーバーの完全に異なるビューです。 「2番目のクエリの結果は間違っていますか?」に関連して、という意味です。質問、それらは間違っているのではなく、パフォーマンス統計の別の側面(つまり、時間枠)に関係しています。
そのため、sys.sysprocesses
を使用したクエリは、「今」しか見ていません。そして、sys.dm_exec_query_stats
を使用したクエリは、SQL Serverサービスの最後の再起動(または明らかにシステムの再起動)以降に何が起こったか(多分)を調べています。一般的なパフォーマンス分析では、sys.dm_exec_query_stats
の方がはるかに優れているように見えますが、繰り返しになりますが、有用な情報は常に欠落しています。また、どちらの場合も、最初に「database_id」値の正確性に関する質問コメント(削除されたため)で@Aaronが行った点も考慮する必要があります(つまり、コードを開始したアクティブなDBのみを反映しています) 、必ずしも「問題」が発生している場所ではありません)。
ただし、すべてのデータベースで今何が起こっているのかを把握する必要がある場合は、sys.dm_exec_connections
、sys.dm_exec_sessions
の組み合わせを使用することをお勧めします。 、およびsys.dm_exec_requests
(非推奨のsys.sysprocesses
ではありません)。クエリはデータベースではなくクエリを参照していることに注意してください。クエリは複数のデータベースにまたがって結合でき、UDFが含まれるためです。 1つ以上のデータベースなどから.
編集:
全体的な懸念が高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;
エラーによる除算のクエリを調整し、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);
sys.dm_exec_query_stats
からのCPUクエリが気に入ったので、拡張しました。それはまだCPUによってランク付けされていますが、より良いサーバープロファイルを得るために他の合計とパーセントを追加しました。これはExcelにうまくコピーされ、[パーセント]列の条件付きカラー形式で、最悪の数値が目立ちます。 「段階的カラースケール」を3色で使用しました。高い値の場合はバラ色、中間の場合は黄色、低い場合は緑。
内部SQLリソースデータベースであるdatabase id 32676
のラベルを追加しました。 CPUと期間を時間に変換して、時間の使用状況をより正確に把握します。
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);