暂无图片
暂无图片
1
暂无图片
暂无图片
8
暂无图片

记一次Sqlserver数据库性能分析

作者:Digital Observer(施嘉伟)
Oracle ACE Pro: Database
PostgreSQL ACE Partner
11年数据库行业经验,现主要从事数据库服务工作
拥有Oracle OCM、DB2 10.1 Fundamentals、MySQL 8.0 OCP、WebLogic 12c OCA、KCP、PCTP、PCSD、PGCM、OCI、PolarDB技术专家、达梦师资认证、数据安全咨询高级等认证
ITPUB认证专家、PolarDB开源社区技术顾问、HaloDB技术顾问、TiDB社区技术布道师、青学会MOP技术社区专家顾问、国内某高校企业实践指导教师
公众号/墨天轮:Digital Observer;CSDN/PGfans:施嘉伟;ITPUB:sjw1933

说明

SQL Server数据库近两天异常卡顿,严重影响程序使用。

评估过程

一、获取当前性能情况

使用SQL server运维工具箱获取巡检报告
人为补充运维工具箱没获取到的内容

二、分析

1、CPU使用率超高

28041743675988_.pic.jpg
该图可详见巡检报告,近7天以来CPU的使用率都超高,故去看巡检报告第六大项的第一项,TOP慢语句,如下图:
image.png
由上图可见,该系统中的慢语句还是比较多的,尤其上图中的红框显示,执行次数竟然达到5000多次,由于巡检报告展示原因,这里只显示SQL标识,现在查询消耗较大的程序语句(查询语句见附录),如下图:
28061743676063_.pic.jpg
这里为了我们这份报告的直观性,我这里将慢语句及其对应的SQL语句都查询出来了,可见,大于1s的语句竟然超过1万行,这明显降低了服务器的性能。
同时,我们观察篮框所示语句,可以清楚的看到基本都是同一个select语句,只是where条件不同罢了,故猜想,肯定是该查询表缺失了索引导致,现在查询该服务器缺失索引情况
28071743676093_.pic.jpg
上图显示为缺失索引影响较大的前10条,尤其是第一行显示的表,添加该索引会有显著性提高,所以,综合以上来看,导致CPU居高不下的原因是由于缺失索引的慢语句所致。

2、内存使用情况

28081743676174_.pic.jpg
上图所示,内存使用在正常范围内,但是根据该服务器的整体特性看,还可以做进一步优化
查询服务器总内存,服务器总内存为24G
28131743991609_.pic.jpg
查询分配给SQL server的使用内存,为16G
image.png
查询当前SQL server已经使用的内存
image.png
根据上图可见,服务器分配给SQL server16G,SQL server目前已经使用16G,虽然整体内存在合理范围内,但是不可避免的会使用一点交换空间,所以,建议分配给SQL server的内存是服务器内存的90%左右,大概20G.

3、数据库使用情况

查询上次(4月1日)巡检和今天(5月27)巡检概况
数据库大小
28151743991779_.pic.jpg
根据以上显示,近两个月数据库增长1G多一点

查询数据文件大小
28161743991806_.pic.jpg

4、文件系统资源

28171743991832_.pic.jpg
根据上图可知,D盘的剩余空间仅剩5G
再看数据库在磁盘上的分布
WeChat0ea598ce81b7a05be199af38ed2e7921.jpg
可见,重要数据库分布在D盘,这是很危险的,虽然数据文件增长较慢,但是可能会因为日志或者其他原因导致D盘空间撑爆,届时SQL server也会由于数据文件或日志文件无法写入而停止运行。

5、会话资源

28191743991894_.pic.jpg
根据上图所示,该服务器的整体会话连接很少,但是这么少的会话就有10个未提交,在结合上边第一条提到的有关缺失索引的语句,极有可能因为占用资源而导致死锁,建议养成一个良好的操作习惯,事务完成之后及时提交。

总结

建议:
1、 根据慢语句、索引缺失添加相关的索引,降低CPU使用率;
2、 增加SQL server的可利用内存,合理分配不浪费;
3、 清理SQL server的日志大小或者清理D盘的空间,防止D盘撑爆;
4、 空闲事务及时提交,避免死锁。

附录:
根据SQL标识查询对应的SQL语句,查询脚本为

SELECT SUBSTRING(st.text, (qs.statement_start_offset/2) + 1, ((CASE statement_end_offset WHEN -1 THEN DATALENGTH(st.text) ELSE qs.statement_end_offset END - qs.statement_start_offset)/2) + 1) FROM sys.dm_exec_query_stats AS qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st WHERE qs.sql_handle=sql_handle --sql_handle 为上图中的sql标识
复制

hhh6.jpg

最后修改时间:2025-04-07 14:47:12
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

筱悦星辰
暂无图片
9天前
评论
暂无图片 1
只要踏实坚定地向前走,你所渴望的终会如约而来。
9天前
暂无图片 1
评论
ora_221
暂无图片
10天前
评论
暂无图片 0
感谢大佬分享,如果查看数据库TOP sql,语句能否分享一下?
10天前
暂无图片 点赞
1
Digital Observer
暂无图片
10天前
回复
暂无图片 0
SELECT TOP 10 qs.total_worker_time / 1000 AS TotalCPUTime_ms, -- 总 CPU 时间(毫秒) qs.execution_count AS ExecutionCount, -- 执行次数 qs.total_worker_time / qs.execution_count / 1000 AS AvgCPUTime_ms, -- 平均 CPU 时间(毫秒) 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 SQLText, DB_NAME(st.dbid) AS DatabaseName, -- 数据库名称 st.objectid AS ObjectID -- 对象 ID FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st ORDER BY TotalCPUTime_ms DESC;
10天前
暂无图片 点赞
回复
R
reddey
暂无图片
11天前
评论
暂无图片 0
大佬,如果查看数据库所分配的内存及CPU使用率,脚本能否分享一下。
11天前
暂无图片 点赞
4
Digital Observer
暂无图片
11天前
回复
暂无图片 0
-- 查询 SQL Server 配置的最大和最小内存 SELECT name AS ConfigurationName, value_in_use AS Memory_MB FROM sys.configurations WHERE name IN ('max server memory (MB)', 'min server memory (MB)'); -- 查询 SQL Server 的 CPU 使用率 SELECT object_name, counter_name, instance_name, cntr_value AS CPUUsage FROM sys.dm_os_performance_counters WHERE counter_name IN ('Processor Time (%)', 'SQL Server: Processor Utilization') AND instance_name = '_Total';
11天前
暂无图片 点赞
回复
R
reddey
暂无图片
11天前
回复
暂无图片 0
@Digital Observer ,感谢大佬的分享。
11天前
暂无图片 点赞
回复
R
reddey
暂无图片
11天前
回复
暂无图片 0
@Digital Observer ,如果没有设置数据库的最大内存,是不是数据库可以使用所有的主机物理内存。
11天前
暂无图片 点赞
回复
Digital Observer
暂无图片
10天前
回复
暂无图片 0
@reddey 是的,但它并不会“无限制”地霸占全部内存,还是会保留一定内存给操作系统使用。
10天前
暂无图片 点赞
回复