TRUNCATE导致CPU异常上涨

午睡醒来收到几封CPU使用率预警邮件。登录对应服务器,打开资源监视器CPU,看到sqlservr.exe进程的CPU达到40%(平常服务器CPU消耗在10%以内)。查看CPU信息跟踪表,近一小时的CPU都维持在40%左右。

图1 CPU使用率预警邮件

图2 CPU信息跟踪表
开启profiler跟踪,筛选CPU>60毫秒的事件。发现有一个存储过程调用非常频繁,而且cpu>90 read>2800。查看此过程,语句很简单,返回记录数很少,表上有对应索引。但从profiler所得开销看,语句肯定没有使用索引。之前遇到类似的问题,只需删除存储过程的计划缓存,cpu、read就降下去了。

--返回做IO数目最多的存储过程以及它们的执行计划(微秒)
SELECT TOP 20 DB_NAME(a.database_id) DBname
      ,OBJECT_NAME(OBJECT_ID ,database_id) ‘proc name‘
      ,a.cached_time
      ,a.last_execution_time
      ,a.execution_count
      ,a.last_logical_reads
      ,a.total_logical_reads / a.execution_count avg_logical_reads
      ,a.total_logical_writes / a.execution_count avg_logical_writes
      ,a.total_physical_reads / a.execution_count avg_physical_reads
      --,a.total_worker_time / a.execution_count AS avg_worker_time
      ,a.total_elapsed_time / a.execution_count avg_elapsed_time
       --,b.text
       ,c.query_plan
       ,a.plan_handle
FROM   sys.dm_exec_procedure_stats    AS a
       CROSS APPLY sys.dm_exec_sql_text(a.sql_handle) b
CROSS APPLY sys.dm_exec_query_plan(a.plan_handle) c
where OBJECT_NAME(OBJECT_ID ,database_id) =‘ProcName‘
ORDER BY
       a.total_logical_reads/a.execution_count desc

--DBCC FREEPROCCACHE(0x0500080094EA1B2F40A1B3DE000000000000000000000000)


图3 处理前消耗情况

图4 处理后消耗情况

图5 半分钟内过程调用情况
问题现象很明显(不定期会重现),就是一个很简单的过程,频繁调用,突然在某个时间点,过程消耗变得很大;只要把对应缓存计划删除,消耗立马降下去。问题的本质是执行计划的变更。过程最开始执行(或者手动执行时)走的是索引查找+键查找;出问题的时候变成了表扫描!

图6 手动执行时的执行计划
查看CPU信息跟踪表,找出此次CPU上涨的起始时间(2015-09-11 11:15:51.447)。查询过程涉及表所依赖的存储过程,查询是否有作业对表(直接或者通过存储过程)进行数据变更,分析表中数据变更与CPU上涨的时间是否吻合。

--表依赖的过程
select name,object_id,text from sys.procedures a,syscomments b
 where a.object_id=b.id and  text like ‘%Table%‘
--作业调用的表/过程
select top 3 sj.name,sjs.command
  from msdb.dbo.sysjobs sj
 inner join msdb.dbo.sysjobsteps sjs
    on sj.job_id=sjs.job_id
 where sjs.command like ‘%TableOrProc%‘

发现有两个过程,被两个作业调用,有对表中数据清空然后再写入。其中一个作业是每天凌晨03:03(排除),另一个作业是每小时执行一次。查看每小时执行一次的作业历史记录,发现在11:15的时候作业耗时46秒,其他时候基本为0。也就是那个时间点对表中数据进行了清空再写入的操作。

select top 20 sj.name,sjh.step_id,sjh.message,sjh.run_status
      ,msdb.dbo.agent_datetime(run_date,run_time),sjh.run_duration
  from msdb.dbo.sysjobhistory sjh
 inner join msdb.dbo.sysjobs sj
    on sjh.job_id=sj.job_id
 where sj.name=‘jobname‘
 order by msdb.dbo.agent_datetime(run_date,run_time) desc


图7 作业历史执行时间
查询统计信息更新时间

图8 统计信息更新时间
数据清空再写入,导致统计信息更新,进而影响执行计划?现在查看统计信息是在11:15更新的,会不会是刚好清空表的时候,程序调用了过程,表中没数据,生成了一个表扫描的执行计划,之后就一直重用这个计划?总之就是表数据变更(清空)影响统计信息,进而影响执行计划的重新生成(表扫描),接着数据再次写入,统计信息会再次更新,但执行计划却还是旧的(表扫描),导致消耗变大。如果手动执行,它会依据新的统计信息,生成新的执行计划(索引查找+键查找)……找个时间后期测试下

时间: 2024-10-19 13:19:04

TRUNCATE导致CPU异常上涨的相关文章

Nodejs mkdirP 模块导致CPU占用高的问题

Nodejs mkdirP 模块导致CPU占用高的问题 近期将nodejs项目部署到服务器上并启动时,发现node进程的cpu占用率在40%左右,当时表示非常不解,刚启动的服务并没有运行什么需要大量消耗cpu的逻辑,且此时还未有请求发送到服务器端. 鉴于这种情况,只能猜测是某段程序在初始化一些东西的时候异常,所以才导致了这种情况. 经过对代码的排查后,最终锁定出为题的代码块如下: router.use(multer({ dest: config.uploadDir, limits:{ fileS

软件调试——CPU异常列表

CPU异常主要分为三类:错误类异常,陷阱类异常和终止类异常 1 错误类异常 Fault CPU遇到该类异常后,会先将CS和EIP(当前发生错误的指令,而不是下一条指令)压栈,然后跳到异常处理函数中,执行完成后恢复到原位置重新执行该指令,如果还有错误,还会再进. 例如内存缺页异常就是错误类异常,CPU遇到缺页异常时会跳转到异常处理,将缺少的内存页从物理内存中置换回来,再恢复重新执行内存访问指令. 2 陷阱类异常 Trap CPU遇到该类异常后,会将CS和EIP压栈,这个EIP就是当前指令的下一条指

解决服务器被挖矿程序攻击导致CPU飙升的问题

通常情况下挖矿程序攻击后导致CPU飙升至80%以上,阿里云cpu监控占比,或者通过命令查看占比 使用top看看cpu占用率,发现sysupdate或networkservice对服务器CPU大量占用的情况 3. 进入proc查看 cd /proc/$PID/       ls -ail进程文件linux目录    发现进程在/etc目录下 4.进入etc目录下,到etc下,除了sysupdate.networkservice 同时还有sysguard.update.sh,除了update.sh其

路径名导致的异常:javax.imageio.IIOException: Can't read input file!

背景: 写了一个测试程序,目的是读取本地的图片,为其打上水印图片.在使用过程中总会遇到:javax.imageio.IIOException: Can't read input file!的错误,最开始以为是图片路径名称写的不对,按照网上的提示换成正斜线和反斜线都不行.后来发现问题的原因是:图片的路径中不能有点(英文点:.); 具体的错误异常提示如下: javax.imageio.IIOException: Can't read input file! at javax.imageio.Imag

Dictionary导致CPU暴涨

中午吃完饭回来,刚想眯一会,突然发现公司预警群报警,某台机器CPU100%,连续三次报警,心里咯噔一下,我新开发的程序就在这上面,是不是我的程序导致的?立马远程,oh my god,果然是. 二话不说,抓紧抓dump,由于是生产环境,所以只抓了两个dump,中间间隔一分钟,立马程序重启. 首先,这个程序从发布以来,cpu从来没有占用如此之高,已经稳定运行近一周时间,期间出现的内存暴涨问题也是由于业务垃圾数据未及时清理,那么唯一的可能性就是早上为了方便查看运行状态,增加的一个小功能导致的,凡事都要

易飞-凭证打印异常(字符中含有空格,自动分行导致显示异常)

在打印凭证中通常会显示自定义或者输入的内容.比如:在电子行业中的插件位置,生产人员经常在作业的时候经常会根据领料单显示的插件位置来作业. 至于为何不根据作业指导书或者BOM等其他方式来确认不在今天我们讨论的范围. 解决办法一:直接行高加大.当然可以,但是如果只是为了一张工单中的几个元件的插件位置显示而已,增加了纸张打印.从成本节约角度不太实用 解决办法二:评估了最多字符也可以在两行中显示完毕的情况下,自动分行差一两个字符的话,就把字体设置小点. 现在问题是,为和第二行中CA9,之后就自动分行了呢

注册了listActivity而没有用导致的异常

昨天在修改一个已有代码的时候没有注意原来的代码是--extends listActivity 结果在加上xml文件后运行后出现了这样的情况:java.lang.RuntimeException: Your content must have a ListView whose id attribute is 'android.R.id.list' 后来仔细观察才知道以前面提到的这个问题.一下是一个网友的解释: "对于以上错误,其实可能是因为我们要实现对ListView中setOnItemClick

记录一次ARP故障导致网络异常

故障现象:单位某台PC出现无法打印故障,提示为下图 该PC重新设置打印机就能够使用但在重启之后无法连接到打印机,并且还会出现连接共享文件的时候会出现类似掉线的情况 分析过程:打印机为网络打印机 内存使用率仅有10% 所以排除1和3 剩下围绕着2的提示来解决 实践过程: 先从网络方面下手,利用IMCP的PING功能对打印服务器,打印机本身进行测试,结果为能PING通. 注!此时发现一个问题,服务器以及其他PC无法PING通本PC! 针对上述所说的故障对本PC进行了网卡驱动更新,系统重装,甚至更换网

Fragment已经被added了导致的异常。

java.lang.IllegalStateException: Fragment already added:  ******Effect 出现的原因是commit方法提交是异步的,所以容易出现,判断的时候是还没有added的状态,但是在真的添加的时候,重复添加了,其实就是一个同步异步的问题. 解决方式其实就是自己添加一个tag,每个fragment一个tag就可以解决重复添加导致的异常了. mAdded = new boolean[]{false, false, false, false,