1. 问题分析
1.1 现象描述
某企业客户内部知识管理系统基于微软SharePoint服务器产品并进行了应用扩展开发,NLB负载均衡部署,后台数据库采用SQL Server 2000 企业版,双核 4C 8G内存两节点群集。在两三年的使用过程中,随着系统用户的增多,出现了数据库服务器CPU占用过高的情况,导致前端访问响应速度慢,经常超时等问题。
1.2 性能计数器分析
用户连接
经过对SQL Server关键性能指标的采集和分析,发现用户连接指标数值过大。用户连接的数据基本保持在700-1000之间,不仅是在忙时段(AM:10),且在闲时段(PM: 6)也基本保持不变,基本可以确定是数据库连接池配置不当或有代码没有释放可用连接,需要通过应用代码进行问题排查。
锁请求/秒
经过向用户的了解,该系统为多数读取,少数写入的系统,但从性能计数器的观测值发现锁请求/秒的指标值平均约为158418.485,最高值可达到558870.266,锁操作总体过大,应该从应用层面进行分析优化。
完全扫描/秒
完全扫描/秒计数器指示有多少不使用索引而进行的全表扫描,测量过程中显示平均值达到100左右,最高值达到832.998,应分析SQL查询语句和数据库索引的对应关系,追加必要的索引以减少全表扫描的次数。
1.3 SQL工具分析
通过使用SQL 事件探查器和查询分析器等工具对SQL Server内部语句执行的性能状况列出了明细,并可将其中的CPU占用较高的任务列出,如第一行显示的大量数据连接导致CPU占用较高、第二行复杂子查询Join下存在部分索引未创建、wf_Instance_track表有大量过期的历史数据时变慢等问题。
1.4 应用代码分析
经过对系统源代码的粗略分析,发现以下一些问题:
a. SqlHelper中的GetConnection每次都是创建一个全新的数据库连接而返回给调用代码,导致连接无法被重用,每次全新创建也会增加服务器的负担;
b. SqlHelper中的TestConnection每次都是创建一个全新的数据库并且打开连接以测试连接的可用性,但是并不关闭就返回了。
c. AcceptUpdate中的SelectDb调用SqlHelper中的GetConnection获得连接后进行数据库查询操作,但使用后并不关闭相应连接
d. AcceptUpdate