如何通过数据库获取特定实例的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);

上面的查询表明问题出在我的数据库之一(将近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过了。这是否意味着第二个查询的结果是错误的?

Answers:


14

尽管我和@Thomas一样,在有关“每个数据库的CPU使用率”的准确性或有用性的问题的评论中,我完全同意@Aaron的意见,但我至少可以回答关于这两个查询为何如此的问题。不同。它们之所以不同的原因将表明哪一个更为准确,尽管更高的准确度仍然相对于具体不准确的准确度,因此仍然不是真正准确;-)。

第一个查询使用sys.dm_exec_query_stats获取CPU信息(即total_worker_time)。如果您转到该DMV的MSDN文档的链接页面,您将看到简短的3句话介绍,其中2句话为我们提供了了解此信息上下文所需的大部分信息(“它的可靠性如何”和“与”相比如何sys.sysprocesses)。这两个句子是:

返回SQL Server中缓存的查询计划的综合性能统计信息。...当从缓存中删除计划时,相应的行将从该视图中删除

第一句话“返回汇总性能统计信息”告诉我们,该DMV中的信息(就像其他几个一样)是累积性的,并不只针对当前正在运行的查询。这也由该DMV中的字段指示,该字段不是Question中查询的一部分,该字段execution_count再次表明这是累积数据。而且,将这些数据进行累加非常容易,因为您可以获得平均值,等等execution_count

第二句话“从缓存中删除的计划也从该DMV中删除”,表明它根本不是一幅完整的图片,尤其是如果服务器已经具有相当完整的计划缓存并且正在加载并且因此计划即将到期有点频繁。此外,大多数DMV会在服务器重置时重置,因此即使计划到期时未删除这些行,它们也不是真实的历史记录。

现在,让我们与进行对比sys.sysprocesses。该系统视图仅显示当前正在运行的内容,就像sys.dm_exec_connectionssys.dm_exec_sessionssys.dm_exec_requests的组合一样(在的链接页上进行了说明sys.dm_exec_sessions)。与sys.dm_exec_query_statsDMV 相比,这是服务器的完全不同的视图,DMV甚至在过程完成后仍保留数据。意思是关于“第二个查询的结果是否错误?” 问题,它们没有错,它们只是与性能统计信息的另一个方面(即时间范围)有关。

因此,使用的查询sys.sysprocesses仅查看“现在”。查询使用的sys.dm_exec_query_stats是(主要)查看自上次重新启动SQL Server服务(或显然是系统重新启动)以来发生的情况。对于一般的性能分析,这似乎sys.dm_exec_query_stats要好得多,但是,它始终会丢失有用的信息。并且,在这两种情况下,您还都需要首先考虑@Aaron在问题注释(已删除)中有关“ database_id”值的准确性的要点(即,它仅反映启动代码的活动数据库) ,不一定是发生“问题”的地方)。

但是,如果你只需要/想什么是所有数据库中现在发生的事情的感觉,可能是因为事情正在放缓,现在,你最好使用的组合sys.dm_exec_connectionssys.dm_exec_sessionssys.dm_exec_requests(而不是过时的sys.sysprocesses)。只需记住,您正在查找/查找查询,而不是数据库,因为查询可以跨多个数据库联接,包括来自一个或多个数据库的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在毫秒?
Kolob Canyon

嗨@KolobCanyon。根据sys.dm_exec_query_stats的文档,total_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和持续时间转换为小时,以更好地了解时间使用情况。

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);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.