首页 > 代码库 > SQL 阻塞(摘自网络)
SQL 阻塞(摘自网络)
/*
所谓的「阻塞」,是指当一个数据库会话中的事务,正在锁定其他会话事务想要读取或修改的资源,
造成这些会话发出的请求进入等待的状态。SQL Server 默认会让被阻塞的请求无限期地一直等待,
直到原来的事务释放相关的锁,或直到它超时 (根据 SET LOCK_TIMEOUT )、服务器关闭、
进程被杀死。一般的系统中,偶尔有短时间的阻塞是正常且合理的;但若设计不良的程序,就可能导致长时间的阻塞,
这样就不必要地锁定了资源,而且阻塞了其他会话欲读取或更新的需求。遇到这种情况,可能就需要手工排除阻塞的状态。
*/
--目前会话中的 lock 超时时间
--执行结果默认为 -1,意即欲访问的对象或记录被锁定时,会无限期等待。
SELECT @@LOCK_TIMEOUT
--后面的 3000,其单位为毫秒,亦即会先等待被锁定的对象 3 秒钟
SET LOCK_TIMEOUT 3000
--SET LOCK_TIMEOUT -1
--在 SSMS 中,开两个会话 (查询窗口) 做测试,会话 A 创建会造成阻塞的事务进程,会话 B 去访问被锁定的记录。
--会话 A
BEGIN TRAN;
UPDATE Orders SET EmployeeID=7 WHERE OrderID=10248
--rollback; --故意不提交或回滚
--会话 B
SELECT * FROM Orders WHERE OrderID=10248
/*
消息 1222,级别 16,状态 51,第 3 行
已超过了锁请求超时时段。
*/
--发生阻塞时,透过以下命令,可看出是哪个进程 session id,阻塞了哪几个进程 session id,且期间经过了多少「毫秒 (ms)」
select blocking_session_id, wait_duration_ms, session_id from sys.dm_os_waiting_tasks
--透过以下两个命令,我们还能看到整个数据库的锁定和阻塞详细信息:
select * from sys.dm_tran_locks
exec sp_lock
--另透过 KILL 命令,可直接杀掉造成阻塞的 process,如下:
KILL 53
--欲解决无限期等待的问题,除了前述的 SET LOCK_TIMEOUT 命令外,还有更省事的做法,
--在表名称后面加上 WITH (NOLOCK) 关键字,表示要求 SQL Server,不必去考虑这个表的锁定状态为何,
--因此也可减少「死锁 (dead lock)」发生的机率。但 WITH (NOLOCK) 不适用 INSERT、UPDATE、DELETE。
SELECT * FROM Orders WITH (NOLOCK) WHERE OrderID=10248
--类似的功能,在 SQL 语句前,先设置「事务隔离级别」为可「脏读 (dirty read)」。
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT * FROM Orders WHERE OrderID=10248
--要知道是否发生了阻塞,当然要看master库的sysprocess表,看看是否有什么进程堵住了别的进程,语句如下:
Select * from master..sysprocesses where blocked > 0
exec sp_lock
--有一个blocked = 51 堵住了很多进程(查看blocked列可见),为了进一步找出发生阻塞的语句,使用如下的语句
dbcc inputbuffer(51);
--spid = 51 这行, mode = X 表示排它锁, status = WAIT表示正在等待(即被阻塞了),dbid = 14 是数据库的id,objid = 206623779 是被锁的对象id,我们可以通过下列函数得到数据库和表:spid = 51 这行, mode = X 表示排它锁, status = WAIT表示正在等待(即被阻塞了),dbid = 14 是数据库的id,objid = 206623779 是被锁的对象id,我们可以通过下列函数得到数据库和表:
Select db_name(@dbid) -----> book_db
select object_name(@objid) -------> t_book
--即book_db库的t_book表被锁住了,这时候再回投仔细检查 p_Book_content 存储过程
--相关资料在book online可以找到,
--关键字: sp_lock , sysprocesses , dbcc inputbuffer , db_name(), object_name()
本文出自 “畅想天空” 博客,请务必保留此出处http://kinwar.blog.51cto.com/3723399/1410842