求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
想个法子找出性能差的SQL
 

发布于2013-3-20

又近放假,发现自己近来有一种放假前做总结的习惯。刚好这两天一个系统总是会出现阵发性的性能问题。经过分析,发现这系统是之前赶出来的系统,什么是赶出来的系统,我想多数人都明白的,很多时候都无可奈何,不多说。现在出问题了,用户骂声一遍。

问题的原因在分析的过程中得到了证实,当时做这个系统时,在没有考虑性能的情况下做出了功能。但是谁又能保证呢?

所以要做些工作:

1. 找出执行时间长的SQL

2. 优化

本文只讲找性能差的SQL,不讲优化,因为优化要对特定的内容。有机会再做一下优化的经验总结。

好,看看要怎样找问题SQL,整个应用中所有的SQL都检查一下是不可能的,就算你真的那么做了,也不可能就没事了,有的看起来没有问题的句子,在生产环境中实际是有问题的。所以,我们就在生产运行过程中,在真实的使用中去想办法找出来。

从两个问题来入手:

问题一,你知道现在正在执行些什么SQL语句?

问题二,正在执行的SQL语句各运行了多长时间了?

在MS SQL中有一个系统视图sys.sysprocesses,它有以下的内容:

所有字段列表:spid kpid blocked waittype waittime lastwaittype waitresource dbid uid cpu physical_io memusage login_time last_batch ecid open_tran status sid hostname program_name hostprocess cmd nt_domain nt_username net_address net_library loginame context_info sql_handle stmt_start stmt_end request_id

以下有图,但是我只想关心其中的一部分内容就够了,我要这个视图中的spid,数据库名、用户名、电脑名等就可以了,具体就看你自己的需要了。

好多的内容在系统视图sys.sysprocesses中,多数在这里用不到,但都是很有用的。不过,要找正在执行的语句,这里就没有,我们要在另两个系统视图中找,一个是sys.dm_exec_connections,如下:

使用以下方式就可以得到正在执行的SQL

1:  SELECT c.session_id,t.text     
2:  FROM sys.dm_exec_connections c     
3:  CROSS APPLY sys.dm_exec_sql_text (c.most_recent_sql_handle) t

第一个问题解决,正在执行什么SQL已可以知道,下边,我们就要从这些SQL中找出执行时间有问题的,比如执行时间大于1分钟的语句,那就要用上边说到的三个视图一起找,可以用以下的方式,你看到有很多的条件可以用,例如你要看或不看某个程序的、某个用户的、某台电脑的SQL,都是可以的。按需灵活设定。有个要注意的是,status要取活动的。

这样第二个问题也已解决,问题SQL已有办法得到,但是不可能时时去执行这个语句,因为我们会有几个人看各自己的部分,并且不可能什么语句都会刚好在有问题时让你发现,我想了一个办法,就是让数据库定时自动找出这些语句,通过DBMail发邮件出来。

通过试验,已初步完成了功能,完整的代码贴上,但是这只是说明我的方法的样例,在实际的应用中要考虑的还有很多问题,在这里就不说。

1:  DECLARE @html NVARCHAR(MAX);    
2:     
3:  with tb    
4:  as    
5:  (    
6:  SELECT c.session_id,t.text 
7:  FROM sys.dm_exec_connections c    
8:  CROSS APPLY sys.dm_exec_sql_text (c.most_recent_sql_handle) t   
9:  )   
10:  select  distinct x.spid,DB_NAME(x.dbid) as dbname,x.last_batch,x.
hostname,x.program_name,x.nt_domain,x.nt_username,tb.text  
11:  into #T    
12:  from sys.sysprocesses x with (nolock)   
 13:  inner join tb on x.spid=tb.session_id  
14:  where x.last_batch
15:  and x.program_name<>'Report Server'  >'Report Server'    
16:  and nt_domain<>'NT AUTHORITY'  
17:  and x.status<>'sleeping'  
18:  and x.hostname<>'HZCSRPTSRV' 
19:     
20:  if exists(select top 1 * from #T)  
21:   begin   
22:   SET @html = '' ;  
23:     
24:   SET @html = @html + CAST(( SELECT 3 [@cellpadding],0 [@cellspacing],
  'font-family:verdana;font-size:10px;' [@style],1 [@border],    
25:                                   ( SELECT [@class] = 'header', 'spid' [text()] FOR XML PATH('th'), TYPE) tr,  
26:                                   ( SELECT [@class] = 'header', 'dbname' [text()] FOR XML PATH('th'), TYPE) tr,  
27:                                   ( SELECT [@class] = 'header', 'last_batch' [text()] FOR XML PATH('th'), TYPE) tr,   
28:                                   ( SELECT [@class] = 'header', 'hostname' [text()] FOR XML PATH('th'), TYPE) tr,   
29:                                   ( SELECT [@class] = 'header', 'program_name' [text()] FOR XML PATH('th'), TYPE) tr,   
30:                                   ( SELECT [@class] = 'header', 'nt_domain' [text()] FOR XML PATH('th'), TYPE) tr,   
31:                                   ( SELECT [@class] = 'header', 'nt_username' [text()] FOR XML PATH('th'), TYPE) tr,   
32:                                   ( SELECT [@class] = 'header', 'text' [text()] FOR XML PATH('th'), TYPE) tr,  
33:                                   ( SELECT      
34:                                     ( SELECT [@class] = 'cell_text', spid [text()] FOR XML PATH('td'), TYPE ),    
35:                                   ( SELECT [@class] = 'cell_text', dbname [text()] FOR XML PATH('td'), TYPE ),   
36:                                   ( SELECT [@class] = 'cell_text', last_batch [text()] FOR XML PATH('td'), TYPE ),    
37:                                   ( SELECT [@class] = 'cell_text', hostname [text()] FOR XML PATH('td'), TYPE ),   
38:                                   ( SELECT [@class] = 'cell_text', program_name [text()] FOR XML PATH('td'), TYPE ),    
39:                                            ( SELECT [@class] = 'cell_text', nt_domain [text()] FOR XML PATH('td'), TYPE ),   
40:                                            ( SELECT [@class] = 'cell_text', nt_username [text()] FOR XML PATH('td'), TYPE ),  
41:                                            ( SELECT [@class] = 'cell_text', text [text()] FOR XML PATH('td'), TYPE )  
42:                                     FROM (     
43:                                    select spid,dbname,last_batch,hostname,program_name,nt_domain,nt_username,text  
44:                                         from #T                                              
45:                                           ) data    
46:                                     FOR XML PATH('tr'), TYPE   
47:                                   )    
48:                              FOR XML PATH('table'), TYPE   
49:                             ) AS VARCHAR(MAX));   
50:   drop table #T;   
51:  --Send Email     
52:  EXEC msdb.dbo.sp_send_dbmail  
53:   @profile_name = 'DBMAIL'   
54:  ,@recipients = 'DarrenXie@QQ.com'     
55:  ,@copy_recipients = 'QQQQQ@QQ.com'     
56:  ,@subject = 'Camstar HZCSRPTSRV long runtime process'   
57:  ,@body = @html     
58:  ,@importance ='High'     
59:  ,@body_format= 'HTML'   
60:  end    
61:   else    
62:  begin  
63:  drop table #T;  
64:  end       

你用以上代码建立SP,再建立JOB定时执行就可以了,一有问题就会发出像以下的内容邮件,你就可以知道相关的内容了,接着你就去做分析优化吧!

最后说明一下,我们可以看到这个方式是基于执行时间的,B/S的程序都差不多是连接数据库执行后就断开的,如果有应用是持久连接的,那就不准确了。

这里只是总结个方法,各自参考参考。

相关文章 相关文档 相关视频



我们该如何设计数据库
数据库设计经验谈
数据库设计过程
数据库编程总结
数据库性能调优技巧
数据库性能调整
数据库性能优化讲座
数据库系统性能调优系列
高性能数据库设计与优化
高级数据库架构师
数据仓库和数据挖掘技术
Hadoop原理、部署与性能调优
 
分享到
 
 


MySQL索引背后的数据结构
MySQL性能调优与架构设计
SQL Server数据库备份与恢复
让数据库飞起来 10大DB2优化
oracle的临时表空间写满磁盘
数据库的跨平台设计
更多...   


并发、大容量、高性能数据库
高级数据库架构设计师
Hadoop原理与实践
Oracle 数据仓库
数据仓库和数据挖掘
Oracle数据库开发与管理


GE 区块链技术与实现培训
航天科工某子公司 Nodejs高级应用开发
中盛益华 卓越管理者必须具备的五项能力
某信息技术公司 Python培训
某博彩IT系统厂商 易用性测试与评估
中国邮储银行 测试成熟度模型集成(TMMI)
中物院 产品经理与产品管理
更多...