SQLServer运维之CPU占用过高

标签: 无 分类: 未分类 创建时间:2022-09-19 02:33:32 更新时间:2025-01-17 10:39:22

前言

一般会用到三个视图sys.sysprocesses ,dm_exec_sessions ,dm_exec_requests,我尝试了如下的问题进行cpu占用过高问题的查询,但是还是没有什么进展:

1.SQL Server Profiler 设定跟踪CPU时间小于500ms,没有什么大的 sql 消耗cpu时间,
2.根据平均cpu时间计算,最多的是 select * from clien 语句
3.定时小时任务都已经关闭的情况下,还是出现 sql cpu 占用百分之六七十的问题
4.查看当前的连接用户数,大部分是ztznr用户执行的操作

原因

由于以下情况,表或索引扫描导致的高逻辑读取:

  • 过期统计信息
  • 缺少索引
  • 参数敏感计划 (PSP) 问题
  • 设计不佳的查询

工作负荷增加

参考文章:
1.为什么 SQLSERVER CPU占用过高 CPU达到100% 看一下当前的数据库用户连接有多少;然后使用下面语句看一下各项指标是否正常,是否有阻塞;如果想看具体的SQL语句可以执行下面的SQL语句;还有查看CPU数和user scheduler数和最大工作线程数。从多次历史经验来看,如果CPU负载持续很高,但内存和IO都还好的话,这种情况下,首先想到的一定是索引问题,十有八九错不了。

1.查询全部连接用户

1
2
3
4
5
USE master
GO
--如果要指定数据库就把注释去掉
SELECT * FROM sys.[sysprocesses] WHERE [spid]>50 --AND DB_NAME([dbid])='gposdb'
SELECT COUNT(*) FROM [sys].[dm_exec_sessions] WHERE [session_id]>50

2.断开全部用户连接

这个不一定能执行成功

1
2
3
4
5
6
7
8
9
10
declare   @sql   varchar(100)
while 1=1
begin
select top 1 @sql = 'kill '+cast(spid as varchar(3))
from master..sysprocesses
where spid > 50 and spid <> @@spid
if @@rowcount = 0
break
exec(@sql)
end
参考文章:
1.快速断开当前数据库的所有连接的方法 这里有很多的方法
2.SQL SERVER如何断开所有连接用户 第一种方法:执行SQL语句;第二种方法:用企业管理器操作

3.使用 SQL Server Profiler

根据参考文章,我使用 SQL Server Profiler 进行查询,结果什么都没有查到

参考文章:
1. SQL Server 2008 R2占用cpu、内存越来越大的两种解决方法 这个是使用了 SQL Server Profiler 工具进行跟踪cpu过高的操作步骤,这里可以指定 cpu 大于等于多少毫秒

4.历史占用大量 CPU 的查询

可以运行以下语句来查找历史占用大量 CPU 的查询:

1
2
3
4
5
6
7
8
9
10
SELECT TOP 10 st.text AS batch_text,
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 statement_text,
(qs.total_worker_time / 1000) / qs.execution_count AS avg_cpu_time_ms,
(qs.total_elapsed_time / 1000) / qs.execution_count AS avg_elapsed_time_ms,
qs.total_logical_reads / qs.execution_count AS avg_logical_reads,
(qs.total_worker_time / 1000) AS cumulative_cpu_time_all_executions_ms,
(qs.total_elapsed_time / 1000) AS cumulative_elapsed_time_all_executions_ms
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(sql_handle) st
ORDER BY(qs.total_worker_time / qs.execution_count) DESC

下面的语句我看不太懂

1
2
3
4
5
6
7
8
9
10
11
SELECT TOP 10
total_worker_time/execution_count AS avg_cpu_cost, plan_handle,
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
FROM sys.dm_exec_query_stats
ORDER BY [avg_cpu_cost] DESC

当前负责高 CPU 活动的查询,请运行以下语句,包含了主机名和登录名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
SELECT TOP 10 s.session_id,
r.status,
r.cpu_time,
r.logical_reads,
r.reads,
r.writes,
r.total_elapsed_time / (1000 * 60) 'Elaps M',
SUBSTRING(st.TEXT, (r.statement_start_offset / 2) + 1,
((CASE r.statement_end_offset
WHEN -1 THEN DATALENGTH(st.TEXT)
ELSE r.statement_end_offset
END - r.statement_start_offset) / 2) + 1) AS statement_text,
COALESCE(QUOTENAME(DB_NAME(st.dbid)) + N'.' + QUOTENAME(OBJECT_SCHEMA_NAME(st.objectid, st.dbid))
+ N'.' + QUOTENAME(OBJECT_NAME(st.objectid, st.dbid)), '') AS command_text,
r.command,
s.login_name,
s.host_name,
s.program_name,
s.last_request_end_time,
s.login_time,
r.open_transaction_count
FROM sys.dm_exec_sessions AS s
JOIN sys.dm_exec_requests AS r ON r.session_id = s.session_id CROSS APPLY sys.Dm_exec_sql_text(r.sql_handle) AS st
WHERE r.session_id != @@SPID
ORDER BY r.cpu_time DESC
参考文章:
1.解决 SQL Server 中 CPU 使用率过高的问题 这是微软提供的几段sql代码,进行cpu过高的查询和解决方法
2.几段排查SQL Server占用CPU过高的SQL
3.如何检查SQL Server CPU瓶颈

5.查询最近一分钟

可以通过sql语句,查询最近一分钟之内的sql执行记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Select --TOP 1000 
ST.text AS '执行的SQL语句',
QS.execution_count AS '执行次数',
QS.total_elapsed_time AS '耗时',
QS.total_logical_reads AS '逻辑读取次数',
QS.total_logical_writes AS '逻辑写入次数',
QS.total_physical_reads AS '物理读取次数',
QS.creation_time AS '执行时间' ,
QS.*
FROM sys.dm_exec_query_stats QS
CROSS APPLY
sys.dm_exec_sql_text(QS.sql_handle) ST
Where QS.creation_time > dateadd(minute,-1,GETDATE()) --当前时间前一分钟
-- Where QS.creation_time BETWEEN '2019-12-04 00:00:00' AND '2019-12-04 11:00:00'
--ORDER BY QS.total_elapsed_time DESC
ORDER BY QS.creation_time DESC

6.查询索引缺失

查询数据cpu过高,多半应该是没有索引导致的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SELECT
DatabaseName = DB_NAME(database_id)
,[Number Indexes Missing] = count(*)
FROM sys.dm_db_missing_index_details
GROUP BY DB_NAME(database_id)
ORDER BY 2 DESC;
SELECT TOP 10
[Total Cost] = ROUND(avg_total_user_cost * avg_user_impact * (user_seeks + user_scans),0)
, avg_user_impact
, TableName = statement
, [EqualityUsage] = equality_columns
, [InequalityUsage] = inequality_columns
, [Include Cloumns] = included_columns
FROM sys.dm_db_missing_index_groups g
INNER JOIN sys.dm_db_missing_index_group_stats s
ON s.group_handle = g.index_group_handle
INNER JOIN sys.dm_db_missing_index_details d
ON d.index_handle = g.index_handle
ORDER BY [Total Cost] DESC;

7.查询连接数

查询每一个数据库的连接数

1
2
3
4
5
6
SELECT name ,count(*) FROM (
SELECT b.name,a.* FROM [Master].[dbo].[SYSPROCESSES] a
INNER JOIN [Master].[dbo].[SYSDATABASES] b
ON a.dbid=b.dbid
)t
GROUP BY t.name

查询每一个连接的信息

1
2
3
4
5
6
7
8
9
10
11
SELECT * FROM 
[Master].[dbo].[SYSPROCESSES] WHERE [DBID]
IN
(
SELECT
[DBID]
FROM
[Master].[dbo].[SYSDATABASES]
WHERE
NAME='你的数据库名称'
)

查询当前全部连接数的详情信息

1
select * from Sys.dm_exec_connections
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。