解决问题时走了一些弯路,但是过程中有些东西可能对以后有点借鉴性,因此记录下来。
客户反映,几天以来系统有一个保存操作在早上10之前一直无法进行,过了10点就OK。
客户的环境为.Net开发的Web应用,用的SQL Server 2000数据库,表中数据量都是几十万、几百万左右,因此一开始重点怀疑10点之前有某些操作锁住了某些表(我们系统确实有些操作,一个工厂需要跑1、2 十分钟半个小时的,就是相当于企业的MRP计算的那种操作),所以导致相关的保存操作被block。从这个点出发,对涉及到被怀疑的一些表的SQL语句进 行Review,浪费了些时间但并没有发现什么问题。
后来在发生问题时登陆进客 户系统环境查看,发现10点以前不仅是保存,涉及到这个对象的查询也无法进行(客户没有发现这一点因此也没有通报给我)。想到就算 update/delete对表加了锁,也不应该导致无法查询,因此估计是索引被独占锁占用而没有释放。从这一点出发,很快将注意力放到每天早上6:50 运行的一个数据库索引重整的Job上,但是从那个Job的程序逻辑方面,也是找不到任何线索,因为程序的逻辑不会导致问题。
然后又等了一天,在发生问题时远程连接到了客户的数据库服务器进行排查。
DBCC CHECKTABLE、DBCC CHECKDB都没有问题,DBCC SHOWCONTIG显示索引状况还不错。
在 企业管理器上查看当前活动(Current Activity),发现报错无法打开,错误信息前后发现了两条,大致意思是一个超时错误、一个说系统已经达到最大锁数量。这个报错弄得人莫名其妙,因为 10点之前使用系统的人很少,数据库服务器CPU使用率相当低,这种情况下不至于达到最大锁数量。企业管理器里面看不了进程,就只能直接查 sysprocesses、syslockinfo了,但是进程有好几百个,因为都是对象的ID、Page号码等,看起来也不直观,就大致的翻了一下,用 怀疑被锁的表ID也没有在syslockinfo里面发现记录。从索引重整Job中找到一个整理被怀疑表索引的语句执行,被block住一直不能结束。因 为有了这个语句被block,从sysprocesses里面很快找到了对应的进程,发现它被另外一个进程block住了,再查,发现就是因为那个进程导 致一系列的进程都被block在那里。查看那个进程,发现是好几天以前就Start了,一直被挂着,它对一个page加了个schema类型的排它锁。这 个进程是客户在某台机器上用企业管理器或者查询分析器对数据库进行操作,出了异常,估计是强行把企业管理器或者查询分析器给结束掉了。以前也曾碰到过这样 的情况,并且强行结束企业管理器或者查询分析器之后,就算重启机器,SQL Server的进程马上又把那个任务调出来继续执行(也不知道SQL Server是在继续执行还是在回滚,反正就是又起起来继续挂在那里)。
问题找到了:那个进程一直占有的page,放的是被怀疑表的索引数据,早上6:50开始的索引重整Job整理这个表的索引时被block住,因为对是schema类型的
排它锁
,导致这个表的所有数据无法访问。因为当时对索引重整Job的超时时间设置成了3个小时,因此到9:50左右索引重整的进程因超时错误退出,所以之后对这个表就可以操作了。
好了,现在的解决方法就是要结束那个进程,但问题是在企业管理器里面无法进入当前活动(Current Activity)中查看进程,也就不能通过企业管理器去结束进程了,以前也从来没有用命令杀过进程,不知道是哪个命令。因此用另外的机器,打开SQL Profiler,然后在企业管理器中找一个进程将它结束,看SQL Profiler里面执行了什么。发现是kill 85这样的语句,呵呵,原来有kill这个命令。OK,在服务器上kill那个进程,问题解决,在企业管理器里面再去查看当前活动(Current Activity),也没有错误了。
SQL Profiler是个很好的东西,你在企业管理器里面可以完成的功能,基本上都可以通过SQL Profiler监测到等价的SQL语句。
例如我以前对系统表不太熟,为了写一些SQL Server管理方面的工具以及ORM针对SQL Server双向交互方面的工具,但是不知道怎么存取表的一些属性,例如列的identity、描述属性,Index的Order、Clustered、 Unique属性等。只要打开Profiler,然后在企业管理器里面操作一下,分析Profiler中的SQL语句,就可以知道是在哪些系统表哪些字段 里面了。
又例如在企业管理器的当前活动(Current Activity)里面查看锁/对象(Locks / Object),用的是下面的存储过程。用sp_helptext可以查看这个存储过程的SQL代码。
sp_MSget_current_activity
52
,
4
,@spid
=
52