Glenn Berry 查询中的疑问(每个数据库的 CPU)

Rac*_*SQL 6 performance sql-server-2008-r2 dmv

请,如果这里不是发布此类问题的地方,请告诉我,我将删除它。

在 Glenn berry 的诊断查询中,有一个查询来显示数据库使用了多少 CPU。这是查询:

-- Get CPU utilization by database (Query 24) (CPU Usage by Database)
WITH DB_CPU_Stats
AS
(SELECT DatabaseID,
        DB_Name(DatabaseID) AS [Database Name],
        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 [CPU Rank],
       [Database Name], [CPU_Time_Ms] AS [CPU Time (ms)], 
       CAST([CPU_Time_Ms] * 1.0 / SUM([CPU_Time_Ms]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [CPU Percent]
FROM DB_CPU_Stats
WHERE DatabaseID <> 32767 -- ResourceDB 
ORDER BY [CPU Rank] OPTION (RECOMPILE);
Run Code Online (Sandbox Code Playgroud)

我想知道,这是查看now使用更多 CPU 的数据库的查询,还是基于过去的信息?

我想知道是什么导致我的服务器 CPU 使用率高:

在此处输入图片说明

嗯,在这张图片中,服务器非常好,但几乎总是我们有 90% 以上的 CPU 使用率,使用sp_whoisactive我什么也找不到(显然我收到了很多查询,但似乎没有一个在敲打服务器).而且读\写非常低(每次)。这就是我要理解的问题。低读/写服务器如何使用这么多CPU?I/O 与 CPU 没有共同之处吗?

我想知道哪个数据库是最重的,以迁移它。

Aar*_*and 6

乍一看,这在我看来近似于每个数据库的 CPU,在历史上sys.dm_exec_query_stats(通常是自上次重新启动以来),但仅适用于当前在缓存中的计划。它还依赖于计划缓存属性,dbid这意味着这是查询的上下文,但不一定是导致工作的数据库。例如,猜测此查询的所有 CPU 在哪里报告:

USE tempdb;
GO
SELECT CONVERT(DATETIME, CONVERT(CHAR(10), CONVERT(DATE, 
  CONVERT(DATETIME, o.create_date)), 120))
FROM msdb.sys.all_objects AS o
CROSS APPLY model.sys.all_columns AS c;
Run Code Online (Sandbox Code Playgroud)

我给你一个提示:它不是msdbmodel

因此,它应该用作大致目标,但不能保证它 100% 的时间都反映了 100% 的现实。您查询它的频率越高(例如,有一些每 n 分钟存储一次快照的自动化作业),它就会越准确,但是除非您的应用程序将每个数据库视为难以穿透的孤岛,否则它仍然会受到数据库上下文的影响而不是查询和数据的实际来源。


Han*_*non 5

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

这意味着这种动态管理视图只能部分满足您的要求。正如 Aaron 在他的回答中所指出的,对特定数据库的归因对查询的上下文很敏感。此外,如果计划没有被缓存很长时间,它们可能在您运行此查询时不在缓存中,因此不会被报告。如果您的系统运行动态查询,您可能会用一次性计划淹没计划缓存,这可能会严重限制此性能指标的可靠性。

您是否打开了“针对临时工作负载进行优化”?使用此查询检查:

SELECT c.name 
    , c.value_in_use
FROM sys.configurations c
WHERE c.name = 'optimize for ad hoc workloads';
Run Code Online (Sandbox Code Playgroud)

您可以使用以下查询来确定计划缓存如何随时间变化:

BEGIN TRY
CREATE TABLE #PC1
(
    refcounts INT
    , usecounts INT
    , size_in_bytes INT
    , memory_object_address varbinary(32)
    , cacheobjtype VARCHAR(255)
    , objtype VARCHAR(255)
    , plan_handle VARBINARY(32)
    , [dbid] INT
    , objectid INT
    , query_plan XML
);
END TRY
BEGIN CATCH
END CATCH
BEGIN TRY
CREATE TABLE #PC2
(
    refcounts INT
    , usecounts INT
    , size_in_bytes INT
    , memory_object_address varbinary(32)
    , cacheobjtype VARCHAR(255)
    , objtype VARCHAR(255)
    , plan_handle VARBINARY(32)
    , [dbid] INT
    , objectid INT
    , query_plan XML
);
END TRY
BEGIN CATCH
END CATCH

TRUNCATE TABLE #PC1;
TRUNCATE TABLE #PC2;

INSERT INTO #PC1
(
    refcounts 
    , usecounts 
    , size_in_bytes 
    , memory_object_address 
    , cacheobjtype 
    , objtype 
    , plan_handle 
    , [dbid] 
    , objectid 
    , query_plan 
)
SELECT 
    refcounts 
    , usecounts 
    , size_in_bytes 
    , memory_object_address 
    , cacheobjtype 
    , objtype 
    , plan_handle 
    , [dbid] 
    , objectid 
    , query_plan 
FROM sys.dm_exec_cached_plans decp
    CROSS APPLY sys.dm_exec_query_plan(decp.plan_handle) t
ORDER BY decp.usecounts DESC;

WAITFOR DELAY '00:01:00';

INSERT INTO #PC2
(
    refcounts 
    , usecounts 
    , size_in_bytes 
    , memory_object_address 
    , cacheobjtype 
    , objtype 
    , plan_handle 
    , [dbid] 
    , objectid 
    , query_plan 
)
SELECT 
    refcounts 
    , usecounts 
    , size_in_bytes 
    , memory_object_address 
    , cacheobjtype 
    , objtype 
    , plan_handle 
    , [dbid] 
    , objectid 
    , query_plan 
FROM sys.dm_exec_cached_plans decp
    CROSS APPLY sys.dm_exec_query_plan(decp.plan_handle) t
ORDER BY decp.usecounts DESC;

SELECT QueryPlan = pc1.query_plan
    , UseCount = pc2.usecounts - pc1.usecounts
    , PlanSize = pc1.size_in_bytes
    , CacheType = pc1.cacheobjtype
    , objType = pc1.objtype
    , DatabaseID = pc1.dbid
FROM #PC1 pc1
    INNER JOIN #PC2 pc2 ON pc1.plan_handle = pc2.plan_handle
WHERE pc2.usecounts - pc1.usecounts > 0
ORDER BY (pc2.usecounts - pc1.usecounts);

SELECT QueryPlan = pc1.query_plan
    , UseCount = pc1.usecounts
    , PlanSize = pc1.size_in_bytes
    , CacheType = pc1.cacheobjtype
    , objType = pc1.objtype
    , DatabaseID = pc1.dbid
FROM #PC1 pc1
WHERE NOT EXISTS 
(
    SELECT 1 
    FROM #PC2 pc2 
    WHERE pc2.plan_handle = pc1.plan_handle
)
ORDER BY (pc1.usecounts);

SELECT QueryPlan = pc2.query_plan
    , UseCount = pc2.usecounts
    , PlanSize = pc2.size_in_bytes
    , CacheType = pc2.cacheobjtype
    , objType = pc2.objtype
    , DatabaseID = pc2.dbid
FROM #PC2 pc2
WHERE NOT EXISTS 
(
    SELECT 1 
    FROM #PC1 pc1 
    WHERE pc1.plan_handle = pc2.plan_handle
)
ORDER BY (pc2.usecounts);
Run Code Online (Sandbox Code Playgroud)

此查询查看计划缓存两次,中间等待 1 分钟。然后它返回 3 个结果集:

  • 第一个显示在第一次和第二次运行之间保留在缓存中的计划。(坚持计划)
  • 第二个显示在第一次运行期间在缓存中的计划,但在第二次运行期间不再在缓存中。(驱逐计划)
  • 第三个显示在第二次运行但不在第一次运行期间在缓存中的计划。(新计划)

如果第一个结果集显示的计划数量远少于第二个结果集,则表明您的服务器缓存中的空间持续不足;这显然表明格伦的查询不会像人们希望的那样可靠。