记一次数据库调优过程(IIS发过来SQLSERVER 的FETCH API_CURSOR语句是神马?)
记一次数据库调优过程(IIS发过来SQLSERVER 的FETCH API_CURSOR语句是神马?)
前几天帮客户优化一个数据库,那个数据库的大小是6G
这麽小的数据库按道理不会有太大的性能问题的,但是客户反应说CPU占用很高,经常达到80%~90%
我检查了任务管理器,确实是SQLSERVER占的CPU
而服务器的内存是16G内存,只占用了7G+
客户的环境:
Windows2008R2
SQLSERVER2005 SP3 64位 企业版
服务器内存:16G
CPU:8核
RDS:阿里云主机
IIS7.5
网站使用ASP技术
着手查找原因
于是就着手检查占用CPU高的原因,检查了很久,发现有一些SQL语句占用CPU很高,而执行的SQL语句如下:
这些是什么语句呢?在msdn上面找不到任何资料,使用下面的SQL语句查看,在[program_name]字段可以看到是IIS发过来的
SELECT * FROM sys.[sysprocesses] WHERE SPID>=50
难道是IIS的bug?然后我又继续在茫茫网海里查找资料,最后终于在paul的博客里找到原因
文章地址:Hunting down the origins of FETCH API_CURSOR and sp_cursorfetch
文章大意
我在调优数据库的时候,使用sqlserver profiler捕获RPC:Completed 事件,可以看到很多类似下面的语句
exec sp_cursorfetch 180150003,32,1,1
exec sp_cursorfetch 180150003,32,1,1
exec sp_cursorfetch 180150003,32,1,1
exec sp_cursorfetch 180150003,32,1,1
你看到这些语句是从session_id为53的session那里发过来的
于是用下面语句看一下session_id为53执行的究竟是什么语句
DBCC INPUTBUFFER (53)
而返回的结果是
FETCH API_CURSOR0000000000000004
您很快意识到这跟服务器游标有一定的关系
如果你使用sys.dm_exec_requests 视图或者sys.dm_exec_connections视图来查看session_id53执行了什么语句
和执行的状态
SELECT t.text
FROM sys.dm_exec_connections c
CROSS APPLY sys.dm_exec_sql_text (c.most_recent_sql_handle) t
WHERE session_id = 53
但是返回的结果依然是
FETCH API_CURSOR0000000000000004
那么还有没有其他的视图来帮助我们呢?我们可以使用sys.dm_exec_cursors视图,将spid代入进去
SELECT c.session_id, c.properties, c.creation_time, c.is_open, t.text
FROM sys.dm_exec_cursors (53) c
CROSS APPLY sys.dm_exec_sql_text (c.sql_handle) t
从结果来看,我们知道语句使用了游标,并且知道游标的属性(scroll locks)和游标创建时间
并且我们看到执行的SQL语句不像是FETCH API_CURSOR或者sp_cursorfetch,而是
SELECT * FROM dbo.FactResellerSales.
本人的处理过程
1、先使用下面的SQL语句找出当前实例下有使用到游标的语句
-- =============================================
-- Author: <桦仔>
-- Blog: <http://www.cnblogs.com/lyhabc/>
-- Create date: <2014/6/3>
-- Description: <获取当前实例下所有的游标语句>
-- =============================================
DECLARE @spid NVARCHAR(100)
DECLARE @SQL NVARCHAR(MAX) DECLARE CurSPID CURSOR
FOR
SELECT [spid]
FROM sys.[sysprocesses]
WHERE [spid] >= 50 OPEN CurSPID
FETCH NEXT FROM CurSPID INTO @spid WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = N'
SELECT cursors.session_id ,
cursors.properties ,
cursors.creation_time ,
cursors.is_open ,
text.text
FROM sys.dm_exec_cursors (' + @spid + ') cursors
CROSS APPLY sys.dm_exec_sql_text(cursors.sql_handle) text'
EXEC(@SQL) FETCH NEXT FROM CurSPID INTO @spid
END
CLOSE CurSPID
DEALLOCATE CurSPID
为什麽上面的脚本要使用游标,因为当时我根据paul的脚本来执行的时候,在活动监视器里能看到使用游标的SQL语句,
但是在SSMS里查询的时候,怎麽也查询不出来,所以才用游标,将使用到游标的语句一网打尽,这里输出的结果要忽略本身这个脚本使用到的游标!!
2、根据输出的结果,发现有几个地方使用了游标,下面只是部分截图
3、把结果拷贝出来,可以发现也是执行的是SELECT 语句
4、因为是ASP程序,没有用到存储过程,于是搜索项目文件,看一下哪个文件有类似的代码
5、找到结果
ASP的语法跟VB是很像的,本人觉得非常羞涩
可以看到server对象创建了一个recordset对象,然后从recordset对象里逐条记录取出来,再做处理,可以看到后续还有
select case....case...case....
就是对取出来的记录再做处理
因为ASP是脚本语言,由IIS来执行,所以在SQLSERVER这边可以看到下面语句的program_name字段是IIS
SELECT * FROM sys.[sysprocesses] WHERE SPID>=50
6、验证一下是否是游标的原因导致CPU高,使用下面的脚本
SELECT * FROM sys.[dm_os_performance_counters]
WHERE [counter_name]='CPU usage %'
AND [object_name]='SQLServer:Resource Pool Stats'
AND [instance_name]='default' SELECT * FROM sys.[dm_os_performance_counters]
WHERE [counter_name]='Active cursors'
AND [object_name]='SQLServer:Cursor Manager by Type'
AND [instance_name]='_Total' --建表
USE [msdb]
GO
CREATE TABLE ActiveCursors
(cntr_value BIGINT,cntr_time DATETIME PRIMARY KEY)
GO
CREATE TABLE CPUUsage
(cntr_value BIGINT,cntr_time DATETIME PRIMARY KEY)
GO --建作业
DECLARE @DBName NVARCHAR(MAX)
DECLARE @job_name sysname SET @DBName='xxx' --★Do SET @job_name='Monitor_CPUUsage_' + @DBName
EXEC msdb.dbo.sp_add_job @job_name=@job_name,
@enabled=1,
@notify_level_eventlog=0,
@notify_level_email=0,
@notify_level_netsend=0,
@notify_level_page=0,
@delete_level=0,
@description=N'监控CPU使用率',
@category_name=N'Database Maintenance',
@owner_login_name=N'sa' --添加监控步骤
DECLARE @job_name SYSNAME
DECLARE @SQL NVARCHAR(MAX)
DECLARE @DBName NVARCHAR(MAX) SET @DBName='xxx' --★Do
SET @job_name='Monitor_CPUUsage_' + @DBName --★Do BEGIN
SET @SQL = N'
USE [msdb]
GO
INSERT INTO CPUUsage(cntr_value,cntr_time)
SELECT cntr_value,GETDATE() FROM sys.[dm_os_performance_counters]
WHERE [counter_name]=''CPU usage %''
AND [object_name]=''SQLServer:Resource Pool Stats''
AND [instance_name]=''default''
'
EXEC msdb.dbo.sp_add_jobstep @job_name = @job_name,
@step_name = N'Monitor', @step_id = 1, @cmdexec_success_code = 0,
@on_success_action = 3, @on_success_step_id = 0, @on_fail_action = 2,
@on_fail_step_id = 0, @retry_attempts = 0, @retry_interval = 0,
@os_run_priority = 0, @subsystem = N'TSQL', @command = @SQL,
@database_name = @DBNAME, @flags = 0 END --创建Monitor作业的调度计划
DECLARE @job_name SYSNAME
DECLARE @SQL NVARCHAR(MAX)
DECLARE @DBName NVARCHAR(MAX) SET @DBName='xxx' --★Do
SET @job_name='Monitor_CPUUsage_' + @DBName --★Do --修改作业的执行时间
EXEC msdb.dbo.sp_add_jobschedule @job_name = @job_name, @name=N'Plan',
@enabled=1,
@freq_type=4,
@freq_interval=1,
@freq_subday_type=2,
@freq_subday_interval=30,
@freq_relative_interval=0,
@freq_recurrence_factor=0,
@active_start_date=20140105,
@active_end_date=99991231,
@active_start_time=2000,
@active_end_time=235959 EXEC msdb.dbo.sp_add_jobserver @job_name = @job_name, @server_name = N'(local)' ------------------------------------------------------------------------------
--建作业
DECLARE @DBName NVARCHAR(MAX)
DECLARE @job_name sysname SET @DBName='xxx' --★Do SET @job_name='Monitor_ActiveCursors_' + @DBName
EXEC msdb.dbo.sp_add_job @job_name=@job_name,
@enabled=1,
@notify_level_eventlog=0,
@notify_level_email=0,
@notify_level_netsend=0,
@notify_level_page=0,
@delete_level=0,
@description=N'监控游标使用',
@category_name=N'Database Maintenance',
@owner_login_name=N'sa' --添加监控步骤
DECLARE @job_name SYSNAME
DECLARE @SQL NVARCHAR(MAX)
DECLARE @DBName NVARCHAR(MAX) SET @DBName='xxxx' --★Do
SET @job_name='Monitor_ActiveCursors_' + @DBName --★Do BEGIN
SET @SQL = N'
USE [msdb]
GO
INSERT INTO ActiveCursors(cntr_value,cntr_time)
SELECT cntr_value,GETDATE() FROM sys.[dm_os_performance_counters]
WHERE [counter_name]=''Active cursors''
AND [object_name]=''SQLServer:Cursor Manager by Type''
AND [instance_name]=''_Total''
'
EXEC msdb.dbo.sp_add_jobstep @job_name = @job_name,
@step_name = N'Monitor', @step_id = 1, @cmdexec_success_code = 0,
@on_success_action = 3, @on_success_step_id = 0, @on_fail_action = 2,
@on_fail_step_id = 0, @retry_attempts = 0, @retry_interval = 0,
@os_run_priority = 0, @subsystem = N'TSQL', @command = @SQL,
@database_name = @DBNAME, @flags = 0 END --创建Monitor作业的调度计划
DECLARE @job_name SYSNAME
DECLARE @SQL NVARCHAR(MAX)
DECLARE @DBName NVARCHAR(MAX) SET @DBName='xxxx' --★Do
SET @job_name='Monitor_ActiveCursors_' + @DBName --★Do --修改作业的执行时间
EXEC msdb.dbo.sp_add_jobschedule @job_name = @job_name, @name=N'Plan',
@enabled=1,
@freq_type=4,
@freq_interval=1,
@freq_subday_type=2,
@freq_subday_interval=30,
@freq_relative_interval=0,
@freq_recurrence_factor=0,
@active_start_date=20140105,
@active_end_date=99991231,
@active_start_time=2000,
@active_end_time=235959 EXEC msdb.dbo.sp_add_jobserver @job_name = @job_name, @server_name = N'(local)'
上面视图里的[object_name]字段和 [instance_name]字段跟你的环境会不一样,所以大家要按照自己的环境来修改
如果是SQLSERVER2005是没有CPU usage %这个counter的,我使用了下面的SQL语句
SELECT SUM([cpu]) FROM sys.[sysprocesses] WHERE SPID>=50
7、画折线图
监控了一天的时间,根据结果使用EXCEL画出折线图
凌晨那段曲线是因为数据库有做清除数据的操作,所以会比较高
游标跟CPU图虽然说不能完全吻合,但是基本能吻合
解决方法
1、修改代码
2、升级到SQL2008,然后使用资源调控器把CPU压下去
最终还是找人修改代码
总结
有时候对一些老旧的程序,例如ASP,可能老一代程序员还会,现在的程序员基本都使用ASP.NET
所以如果可能,还是跟上技术的脚步,不然出问题了,没有人维护就麻烦了
如有不对的地方,欢迎大家拍砖o(∩_∩)o
记一次数据库调优过程(IIS发过来SQLSERVER 的FETCH API_CURSOR语句是神马?)的更多相关文章
- 数据库调优过程(一):SqlServer批量复制(bcp)[C#SqlBulkCopy]性能极低问题
背景 最近一段给xx做项目,这边最头疼的事情就是数据库入库瓶颈问题. 环境 服务器环境:虚拟机,分配32CPU,磁盘1.4T,4T,5T,6T几台服务器不等同(转速都是7200r),内存64G. 排查 ...
- 数据库调优过程(二):找到IO不存在问题,而是sqlserver单表写入IO瓶颈
物理机上测试IO是否为瓶颈: 使用一个死循环insert into测试数据库最大写入速度: use [iTest]; declare @index int; ; begin ; INSERT into ...
- MySQL面试必考知识点:揭秘亿级高并发数据库调优与最佳实践法则
做业务,要懂基本的SQL语句: 做性能优化,要懂索引,懂引擎: 做分库分表,要懂主从,懂读写分离... 数据库的使用,是开发人员的基本功,对它掌握越清晰越深入,你能做的事情就越多. 今天我们用10分钟 ...
- [转]10分钟梳理MySQL知识点:揭秘亿级高并发数据库调优与最佳实践法则
转:https://mp.weixin.qq.com/s/RYIiHAHHStIMftQT6lQSgA 做业务,要懂基本的SQL语句: 做性能优化,要懂索引,懂引擎: 做分库分表,要懂主从,懂读写分离 ...
- Mysql数据库调优和性能优化的21条最佳实践
Mysql数据库调优和性能优化的21条最佳实践 1. 简介 在Web应用程序体系架构中,数据持久层(通常是一个关系数据库)是关键的核心部分,它对系统的性能有非常重要的影响.MySQL是目前使用最多的开 ...
- Mysql数据库调优和性能优化
1. 简介 在Web应用程序体系架构中,数据持久层(通常是一个关系数据库)是关键的核心部分,它对系统的性能有非常重要的影响.MySQL是目前使用最多的开源数据库,但是mysql数据库的默认设置性能非常 ...
- 一次jvm调优过程
jvm调优实战 前端时间把公司的一个分布式定时调度的系统弄上了容器云,部署在kubernetes,在容器运行的动不动就出现问题,特别容易jvm溢出,导致程序不可用,终端无法进入,日志一直在刷错误,ku ...
- mysql数据库 调优
mysql调优硬件配置网络带宽mysql运行参数慢查询日志网络架构多实例(一台服务器上运行多个数据库服务)分库分表 当一台数据库服务器处理客户端的请求慢时,可能是哪些原因造成? 硬件配置低:(内存 c ...
- 记一次JVM调优之旅(斗争full gc)
俗话说技多不压身,当年苦读<深入理解JVM>还专门整理了笔记,现在就用上了- 笔记 http://www.cnblogs.com/syjkfind/p/3901774.html [症状] ...
随机推荐
- JSON之Asp.net MVC C#对象转JSON,DataTable转JSON,List转JSON,JSON转List,JSON转C#对象
一.JSON解析与字符串化 JSON.stringify() 序列化对象.数组或原始值 语法:JSON.stringify(o,filter,indent) o,要转换成JSON的对象.数组或原始值 ...
- [JavaScript 随笔] 垃圾回收
在 JavaScript 中,由于垃圾回收是自动进行的,所以人们在编码时可能不太会注意这方面.但事实是,一些 webapp 在使用一段时间后,会出现卡顿的现象,特别是那些单页应用,包括 WebView ...
- sqoop1.99.6 update导出语句
我们采用sqoop-export插入数据的时候,如果主键已经存在了,插入会失败.想要根据主键判断是否要进行insert操作还是update操作,sqoop提供了update语法.示例 sqoop -- ...
- (转)SpyGlass工具介绍
Spyglass工具有五大模块: lint, CDC(多时钟域检查), LP(低功耗),Constraint(约束),DFT(可测试性). 一,在RTL层面上预估芯片性能,从而引导设计人员开发出更加 ...
- sql中 查询条件出现单引号和特殊字符处理
1.两个单引号转为一个单引号 example: select * from tb where name=' '' ' 2.如果出现 "_","%" 需要用 ...
- nwe
SELECT SUBSTR('20150601', 1, 6) AS CALC_MONTH, CHN.EMPLOYEE_CODE, CHN.CHANNEL_TYPE, ...
- 灭顶之灾之网络电视精灵——S2 2.8
从前,有一个神奇的东西叫做搞搞精灵 关于他,有一段历史. 哎呀!我去!写不下去了. -.-以上玩笑 首先需求分析 TreeView显示两种频道 TypeA和TypeB 所以创建三个类 ChannelB ...
- 使用max() 函数
/********************************* 代码功能:使用串口输出a和b的最大值 使用函数:max(a,b); 创作时间:2016*11*04 作者邮箱:jikexianfe ...
- 浅析Android中ndk-build支持的参数
在解决Android Studio中编译native code出现的问题时,发现Android Studio使用了完整的ndk-build命令进行编译,参数众多.故在此做一个说明,以便大家可以根据偏好 ...
- SQL语句-批量插入表(表数据插表)
批量插入表(表数据插表) ****1.INSERT INTO SELECT语句语句形式为:Insert into Table2(field1,field2,...) select value1,val ...