一次惨痛的数据库锁死经历(都是加锁的祸根,索引的祸根)
数据库锁我就不多说了,相信大家都知道,先说说我的经历吧
上午10左右,突然平台用户登录缓慢,甚至无法登录,但登录成功之后网站速度很快,没有任何异常
因此我们判断是登录方法出了问题
于是赶紧检查代码进行本地调试结果发现是访问数据库的其实两个表缓慢,因在在登录时需要记录日志等。
于是我优先处理方案是把这两行记录日志的代码给注释上传,先让用户正常使用,少记一点日志也没事
然后马上打开数据库日志库进行排查问题
然后我通过一条
[SQL] 纯文本查看 复制代码 /****** Script for SelectTopNRows command from SSMS ******/
SELECT TOP 1000 [UserId]
,[LoginIP]
,[LoginDate]
,[LoginRecordType]
FROM [jjoobb_statistic].[dbo].[Pub_UserLoginLog]
发现查询很快,没有任务情况,
然后又加了一个条件
[SQL] 纯文本查看 复制代码 SELECT TOP 1000 [UserId]
,[LoginIP]
,[LoginDate]
,[LoginRecordType]
FROM [jjoobb_statistic].[dbo].[Pub_UserLoginLog] where UserId=23
好吧这一条直接就查不出来了,一直在执行无响应,很明显是整个表甚至整个库被锁了
这样一个有索引的简单语句,应该是瞬间就能执行完成的,现在竟然无响应。
然后我通过以下语句查看锁的占用情况
[SQL] 纯文本查看 复制代码 --死锁检测
use master
Select * from sysprocesses where blocked<>0
--找到SPID
exec sp_lock
--根据SPID找到OBJID
select object_name(2073058421)
--根据OBJID找到表名
执行如下
很明显有很多的锁,整个数据库怕是什么也查不到了。
没办法现在只能强制结束了,
执行如下语句
[SQL] 纯文本查看 复制代码
Exec dbo.sp_lock
begin
declare @i int--定义要清除的线程id
declare @SQL nvarchar(3000);
set @i =0;
while(@i<10000)
begin
--清除所有的占用线程
set @SQL=N'kill '+convert(varchar(20),@i)
exec sp_executesql @SQL;
set @i=@i+1;
end
end
然后没过几分钟就全部Ok了,
但问题还是没有找到,于是就打开锁检查工具
通过检查发现其实一个表不管怎么查数据都慢,
好吧,因为我们的工程师忘记给这个表建索引了,时间久了数据增多,现在已经有40W数据了,外加上高频次的访问
导致整个数据库被锁,惨痛的教训啊。
|