是否可以按数据库分析CPU利用率?
我理想地为SQL服务器寻找任务管理器类型接口,但不是查看每个PID(如taskmgr
)或每个SPID(如spwho2k5
)的CPU利用率,而是想要查看每个数据库的总CPU利用率。假设一个SQL实例。
我意识到可以编写工具来收集这些数据并对其进行报告,但我想知道是否有任何工具可以让我看到哪些数据库对sqlservr.exe
CPU贡献最大的实时视图负荷。
答案 0 :(得分:81)
排序。检查此查询:
SELECT total_worker_time/execution_count AS AvgCPU
, total_worker_time AS TotalCPU
, total_elapsed_time/execution_count AS AvgDuration
, total_elapsed_time AS TotalDuration
, (total_logical_reads+total_physical_reads)/execution_count AS AvgReads
, (total_logical_reads+total_physical_reads) AS TotalReads
, execution_count
, SUBSTRING(st.TEXT, (qs.statement_start_offset/2)+1
, ((CASE qs.statement_end_offset WHEN -1 THEN datalength(st.TEXT)
ELSE qs.statement_end_offset
END - qs.statement_start_offset)/2) + 1) AS txt
, query_plan
FROM sys.dm_exec_query_stats AS qs
cross apply sys.dm_exec_sql_text(qs.sql_handle) AS st
cross apply sys.dm_exec_query_plan (qs.plan_handle) AS qp
ORDER BY 1 DESC
这将使计划缓存中的查询按照他们用完了多少CPU的顺序。您可以定期运行此命令,例如在SQL代理作业中,并将结果插入表中,以确保数据在重新启动后仍然存在。
当您阅读结果时,您可能会意识到为什么我们无法将这些数据直接关联回单个数据库。首先,单个查询也可以通过这样的技巧隐藏其真正的数据库父级:
USE msdb
DECLARE @StringToExecute VARCHAR(1000)
SET @StringToExecute = 'SELECT * FROM AdventureWorks.dbo.ErrorLog'
EXEC @StringToExecute
查询将在MSDB中执行,但它会从AdventureWorks轮询结果。我们应该在哪里分配CPU消耗?
当你:
时情况变得更糟它一直在继续。这就是为什么在查询级别而不是数据库级别进行性能调整是有意义的。
在SQL Server 2008R2中,Microsoft引入了性能管理和应用程序管理功能,这些功能可让我们将单个数据库打包到可分发和可部署的DAC包中,并且它们具有很好的功能,可以更轻松地管理单个数据库及其数据库的性能应用。但是,它仍然无法满足您的需求。
有关更多内容,请查看T-SQL repository at Toad World's SQL Server wiki (formerly at SQLServerPedia)。
在1/29更新,包括总数而不仅仅是平均数。
答案 1 :(得分:15)
SQL Server(从2000开始)将安装性能计数器(可从性能监视器或Perfmon中查看)。
其中一个计数器类别(来自SQL Server 2005的安装是:) - SQLServer:数据库
每个数据库都有一个实例。然而,可用的计数器不提供CPU%利用率计数器或类似的东西,尽管有一些速率计数器可用于获得CPU的良好估计。例如,如果您有2个数据库,并且数据库A上测量的速率是20个事务/秒,数据库B上测量的速率是80个传输/秒 - 那么您会知道A大约占总CPU的20%,并且B对其他80%的贡献。
这里存在一些缺陷,因为假设所有正在完成的工作都是CPU绑定的,当然这对数据库来说并非如此。但我相信这将是一个开始。
答案 2 :(得分:6)
这是一个查询,它将显示导致高负载的实际数据库。它依赖于可能在低内存情况下频繁刷新的查询缓存(使查询不那么有用)。
select dbs.name, cacheobjtype, total_cpu_time, total_execution_count from
(select top 10
sum(qs.total_worker_time) as total_cpu_time,
sum(qs.execution_count) as total_execution_count,
count(*) as number_of_statements,
qs.plan_handle
from
sys.dm_exec_query_stats qs
group by qs.plan_handle
order by sum(qs.total_worker_time) desc
) a
inner join
(SELECT plan_handle, pvt.dbid, cacheobjtype
FROM (
SELECT plan_handle, epa.attribute, epa.value, cacheobjtype
FROM sys.dm_exec_cached_plans
OUTER APPLY sys.dm_exec_plan_attributes(plan_handle) AS epa
/* WHERE cacheobjtype = 'Compiled Plan' AND objtype = 'adhoc' */) AS ecpa
PIVOT (MAX(ecpa.value) FOR ecpa.attribute IN ("dbid", "sql_handle")) AS pvt
) b on a.plan_handle = b.plan_handle
inner join sys.databases dbs on dbid = dbs.database_id
答案 3 :(得分:1)
我认为你的问题的答案是否定的。
问题是计算机上的一个活动可能会导致多个数据库的加载。如果我有一个从配置数据库读取的进程,记录到日志数据库,并根据类型将事务移入和移出各种数据库,我该如何对CPU使用进行分区?
您可以将CPU利用率除以事务负载,但这又是一个可能误导您的粗略指标。例如,您如何将事务日志传送从一个数据库划分到另一个数据库? CPU负载是读数还是写入?
您最好查看计算机的事务率及其导致的CPU负载。您还可以对存储过程进行概要分析,看看它们是否占用了过多的时间;但是,这不会得到你想要的答案。
答案 4 :(得分:1)
考虑到上述所有内容。
从SQL Server 2012开始(可能是2008年?), sys.dm_exec_sessions 中有 database_id 列。
它使我们可以轻松计算当前连接的会话的每个数据库的cpu。如果会话已断开连接,则其结果已消失。
select session_id, cpu_time, program_name, login_name, database_id
from sys.dm_exec_sessions
where session_id > 50;
select sum(cpu_time)/1000 as cpu_seconds, database_id
from sys.dm_exec_sessions
group by database_id
order by cpu_seconds desc;
答案 5 :(得分:0)
看看SQL Sentry。它可以满足您的所有需求。
此致 利芬
答案 6 :(得分:0)
你看过SQL分析器吗?
采用标准的“T-SQL”或“存储过程”模板,调整字段以按数据库ID分组(我想你必须使用数字,你没有得到数据库名称,但它很容易找到使用exec sp_databases获取列表)
运行一段时间,您将获得总CPU数/磁盘IO /等等。这可以为您提供每个数据库使用的CPU比例。
如果您同时监视PerfMon计数器(将数据记录到SQL数据库),并对SQL事件探查器(记录到数据库)执行相同操作,则可能能够关联两个人在一起。
即便如此,它应该为您提供足够的线索,以便更详细地了解哪个DB值得关注。然后,仅使用该数据库ID再次执行相同的操作,并查找最昂贵的SQL /存储过程。
答案 7 :(得分:0)
请检查此查询:
SELECT
DB_NAME(st.dbid) AS DatabaseName
,OBJECT_SCHEMA_NAME(st.objectid,dbid) AS SchemaName
,cp.objtype AS ObjectType
,OBJECT_NAME(st.objectid,dbid) AS Objects
,MAX(cp.usecounts)AS Total_Execution_count
,SUM(qs.total_worker_time) AS Total_CPU_Time
,SUM(qs.total_worker_time) / (max(cp.usecounts) * 1.0) AS Avg_CPU_Time
FROM sys.dm_exec_cached_plans cp
INNER JOIN sys.dm_exec_query_stats qs
ON cp.plan_handle = qs.plan_handle
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st
WHERE DB_NAME(st.dbid) IS NOT NULL
GROUP BY DB_NAME(st.dbid),OBJECT_SCHEMA_NAME(objectid,st.dbid),cp.objtype,OBJECT_NAME(objectid,st.dbid)
ORDER BY sum(qs.total_worker_time) desc