Windows客户端找到所有性能计数器可以通过命令:
CMD: typeperf -q > F:\Performance.txt
对于我们DBA来讲,数据库最大性能障碍无非是 CPU/DISK/MEMORY 分别介绍下面三巨头;
PerfCounter=Processor_Total,"\Processor(_Total)\% Processor Time",30 (阈值:>85%)
全实例 指处理器执行非闲置线程时间的百分比,测量处理器繁忙的时间 这个计数器设计成用来作为处理器活动的主要指示器,可以选择单个CPU实例;
PerfCounter=ProcessorUserTime,"\Processor(_Total)\% User Time",30
非内核级应用程序占用的时间.表示耗费CPU的数据库操作如order by group by等。如果该值很高,可增加合适的索引和优化语句,尽量使用简单
的表联接,水平分割大表格等方法来降低该值。
PerfCounter=Processor_sqlservr,"\Process(sqlservr)\% Processor Time",30 (阈值:>80%)
指定单个进程消耗的CPU时间占比.参考总的CPU消耗(% Processor Time(_Total))
下图是本地机测试演示用的,所以都很低;
cpu 持续很高,要留意下并行度、是否是缺少索引,导致逻辑读多和全表扫描多导致复杂查询占有大量CPU;
下图的案例 是语句执行时间和cpu、执行时间对比,明显能看出出现了CXPACKET等待;
参考:32个CPU 最大并行度设置成8或者4;如果是OATP事物级数据库,可以建议设置为1;
并行度开销阈值:越小代表越容易走并行执行;默认值为5;
最常用的方法处理cpu占有高的问题:
- 添加索引降低语句开销,执行需要的资源消耗少了消耗的CPU 自然相对就少了。
- 降低语句复杂度,让SQL Server执行高效(同样也是降低资源消耗的方法)。
- 分析语句是否可以采用串行计划。
- 前端程序尽量参数化减少语句的编译消耗。
之前也遇到过CPU飙高,远程卡的动不了;
首先看下当前数据库连接用户数:
SELECT * FROM SYS.SYSPROCESSES WHERE SPID>50 --AND SPID<>@@SPID --AND BLOCKED>0;
SELECT COUNT (*) FROM SYS.DM_EXEC_SESSIONS WHERE SESSION_ID>50 --AND SPID<>@@SPID --AND BLOCKED>0;
其次首先查下Top 10 CPU消耗资源
SELECT TOP 10
A.SESSION_ID,
A.REQUEST_ID,
A.BLOCKING_SESSION_ID,
B.[TEXT],
A.STATUS,
A.WAIT_TYPE,
A.WAIT_TIME,
A.WAIT_RESOURCE,
A.CPU_TIME,
A.READS,
A.WRITES,
A.LOGICAL_READS,
A.ROW_COUNT,
DB_NAME(A.DATABASE_ID) AS [DB_NAME],
C.query_plan
FROM
SYS.dm_exec_requests A
CROSS APPLY SYS.DM_EXEC_SQL_TEXT(SQL_HANDLE) B
CROSS APPLY SYS.DM_EXEC_QUERY_PLAN(PLAN_HANDLE) C
WHERE A.SESSION_ID <>@@SPID
AND A.SESSION_ID >50
ORDER BY A.CPU_TIME DESC
查看数据库cpu个数、用户scheduler数目以及最大工作线程;满的时候检查blocking;
SELECT CPU_COUNT,SCHEDULER_COUNT,MAX_WORKERS_COUNT FROM SYS.dm_os_sys_info
当前数据库最大workers
select * from sys.dm_os_schedulers
视图:[sys].[dm_os_wait_stats]
关联这个视图查看等待任务数目:
SELECT TOP 10
[session_id],
[request_id],
[start_time] AS ‘开始时间‘,
[status] AS ‘状态‘,
[command] AS ‘命令‘,
dest.[text] AS ‘sql语句‘,
DB_NAME([database_id]) AS ‘数据库名‘,
[blocking_session_id] AS ‘正在阻塞其他会话的会话ID‘,
der.[wait_type] AS ‘等待资源类型‘,
[wait_time] AS ‘等待时间‘,
[wait_resource] AS ‘等待的资源‘,
[dows].[waiting_tasks_count] AS ‘当前正在进行等待的任务数‘,
[reads] AS ‘物理读次数‘,
[writes] AS ‘写次数‘,
[logical_reads] AS ‘逻辑读次数‘,
[row_count] AS ‘返回结果行数‘
FROM sys.[dm_exec_requests] AS der
INNER JOIN [sys].[dm_os_wait_stats] AS dows
ON der.[wait_type]=[dows].[wait_type]
CROSS APPLY
sys.[dm_exec_sql_text](der.[sql_handle]) AS dest
WHERE [session_id]>50
ORDER BY [cpu_time] DESC
最后再看下总体CPU占有资源消耗;
SELECT TOP 10
total_worker_time/execution_count AS avg_cpu_cost,
execution_count,
(SELECT SUBSTRING(text, statement_start_offset/2 + 1,
(CASE WHEN statement_end_offset = -1
THEN LEN(CONVERT(nvarchar(max), text)) * 2
ELSE statement_end_offset
END - statement_start_offset)/2)
FROM sys.dm_exec_sql_text(sql_handle)) AS query_text,
C.query_plan
FROM sys.dm_exec_query_stats
cross apply sys.dm_exec_query_plan(plan_handle) c
ORDER BY [avg_cpu_cost] DESC