设为首页 收藏本站
查看: 617|回复: 0

[经验分享] 记一次数据库调优过程(IIS发过来SQLSERVER 的FETCH API_CURSOR语句是神马?)

[复制链接]

尚未签到

发表于 2015-8-12 10:21:53 | 显示全部楼层 |阅读模式
记一次数据库调优过程(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语句如下:
DSC0000.jpg
  
  这些是什么语句呢?在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
  
  您很快意识到这跟服务器游标有一定的关系
DSC0001.png
  
  如果你使用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
DSC0002.jpg
  从结果来看,我们知道语句使用了游标,并且知道游标的属性(scroll locks)和游标创建时间
  并且我们看到执行的SQL语句不像是FETCH API_CURSOR或者sp_cursorfetch,而是



SELECT * FROM dbo.FactResellerSales.
  本人的处理过程
  1、先使用下面的SQL语句找出当前实例下有使用到游标的语句



-- =============================================
-- Author:      <桦仔>
-- Blog:        <http://www.iyunv.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、根据输出的结果,发现有几个地方使用了游标,下面只是部分截图
DSC0003.jpg
  
  3、把结果拷贝出来,可以发现也是执行的是SELECT 语句
DSC0004.jpg
  
  4、因为是ASP程序,没有用到存储过程,于是搜索项目文件,看一下哪个文件有类似的代码
DSC0005.jpg
  5、找到结果
DSC0006.jpg
DSC0007.jpg
  ASP的语法跟VB是很像的,本人觉得非常羞涩
  可以看到server对象创建了一个recordset对象,然后从recordset对象里逐条记录取出来,再做处理,可以看到后续还有
  select case....case...case....
  就是对取出来的记录再做处理
  
  因为ASP是脚本语言,由IIS来执行,所以在SQLSERVER这边可以看到下面语句的program_name字段是IIS



SELECT * FROM sys.[sysprocesses] WHERE SPID>=50
  
  6、验证一下是否是游标的原因导致CPU高,使用下面的脚本


DSC0008.gif DSC0009.gif


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)'
View Code  上面视图里的[object_name]字段和 [instance_name]字段跟你的环境会不一样,所以大家要按照自己的环境来修改
  如果是SQLSERVER2005是没有CPU usage %这个counter的,我使用了下面的SQL语句



SELECT SUM([cpu]) FROM sys.[sysprocesses] WHERE SPID>=50
  
  7、画折线图
  监控了一天的时间,根据结果使用EXCEL画出折线图
DSC00010.jpg
DSC00011.jpg
  
  凌晨那段曲线是因为数据库有做清除数据的操作,所以会比较高
  游标跟CPU图虽然说不能完全吻合,但是基本能吻合
  
  解决方法
  1、修改代码
  2、升级到SQL2008,然后使用资源调控器把CPU压下去
  
  最终还是找人修改代码

  总结
  有时候对一些老旧的程序,例如ASP,可能老一代程序员还会,现在的程序员基本都使用ASP.NET
  所以如果可能,还是跟上技术的脚步,不然出问题了,没有人维护就麻烦了
  
  如有不对的地方,欢迎大家拍砖o(&cap;_&cap;)o

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-97818-1-1.html 上篇帖子: WCF服务寄宿IIS与Windows服务 下篇帖子: IIS 7 Smooth Streaming技术在Silverlight 3中的应用
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表