阻塞,是指当一个数据库会话中的事务,正在锁定其他会话事务想要读取或修改的资源,造成这些会话发出的请求进入等待的状态。SQL Server 默认会让被阻塞的请求无限期地一直等待,直到原来的事务释放相关的锁,或直到它超时 、服务器关闭、进程被杀死。
由于 SQL Server 的「事务隔离级别」默认是 READ COMMITTED (事务期间别人无法读取),加上 SQL Server 的锁定造成阻塞时,默认是别的进程必须无限期等待 (LOCK_TIMEOUT = -1)。结果这些大量的客户端 request 无限期等待永远不会提交或回滚的事务,并一直占用着 connection pool 中的资源,最后造成 connection pooling 连接数目超载。
由于 SQL Server 的「事务隔离级别」默认是 READ COMMITTED (事务期间别人无法读取),加上 SQL Server 的锁定造成阻塞时,默认是别的进程必须无限期等待 (LOCK_TIMEOUT = -1)。结果这些大量的客户端 request 无限期等待永远不会提交或回滚的事务,并一直占用着 connection pool 中的资源,最后造成 connection pooling 连接数目超载。
默认的SQL Server 会话中的 lock 超时时间,可用以下的命令:
SELECT @@LOCK_TIMEOUT
执行结果默认为 -1,意即欲访问的对象或记录被锁定时,会无限期等待。若欲更改当前会话的此值,可用下列命令:
SET LOCK_TIMEOUT 3000
后面的 3000,其单位为毫秒,亦即会先等待被锁定的对象 3 秒钟。若事务仍未释放锁,则会抛回如下代号为 1222 的错误信息,可供程序员编程时做相关的逾时处理:
消息 1222,级别 16,状态 51,第 3 行
已超过了锁请求超时时段。
若将 LOCK_TIMEOUT 设置为 0,亦即当欲访问对象被锁定时,完全不等待就抛回代号 1222 的错误信息。此外,此一 SET LOCK_TIMEOUT 命令,影响范例只限当前会话 (进程),而非对某个表做永久的设置。
//模拟出现死锁的案例// ---DEAD LOCK CASE--- --建2张表 CREATE TABLE T1(ID INT) INSERT INTO T1 VALUES(1) CREATE TABLE T2(ID INT) INSERT INTO T2 VALUES(1) --事务1,会同时锁定表T1和表T2 ---STEP 1 BEGIN TRAN UPDATE T1 SET ID=1 UPDATE T2 SET ID=1 --事务2,由于表T2已经被锁定,所以当执行下面的语句的是时候,会出现死锁 --step 2 BEGIN TRAN UPDATE T2 SET ID=5
如何查看SQL Server 2008的死锁
方法一:
1.查询分析器执行 sp_lock 查看
2.右键服务器-选择“活动和监视器”,查看进程选项。注意“任务状态”字段。
方法二:
--每秒死锁数量 SELECT * FROM sys.dm_os_performance_counters WHERE counter_name LIKE 'Number of Deadlocksc%'; --查询当前阻塞 WITH CTE_SID ( BSID, SID, sql_handle ) AS ( SELECT blocking_session_id , session_id , sql_handle FROM sys.dm_exec_requests WHERE blocking_session_id <> 0 UNION ALL SELECT A.blocking_session_id , A.session_id , A.sql_handle FROM sys.dm_exec_requests A JOIN CTE_SID B ON A.SESSION_ID = B.BSID ) SELECT C.BSID , C.SID , S.login_name , S.host_name , S.status , S.cpu_time , S.memory_usage , S.last_request_start_time , S.last_request_end_time , S.logical_reads , S.row_count , q.text FROM CTE_SID C JOIN sys.dm_exec_sessions S ON C.sid = s.session_id CROSS APPLY sys.dm_exec_sql_text(C.sql_handle) Q ORDER BY sid
执行的效果如下:
在压力测试过程中,不间断的按F5键执行上面的SQL语句,如果出现死锁或者堵塞现象,就会在执行结果中罗列出来。如果每次连续执行SQL,都有死锁或者堵塞出现,说明死锁或者堵塞的比较严重。