SQL Server可以先获得细粒度的锁(例如行或页),在某些情况下将细粒度锁升级为更粗粒度的锁(例如,表)。
例如单个语句获得至少5000个锁,就会触发锁升级,如果由于锁冲突而导致无法升级锁,则SQL Server每当获取1250个新锁时出发锁升级。
当多个事务都需要对某一资源进行锁定时,默认情况下会发生阻塞。被阻塞的请求会一直等待,直到原来的事务释放相关的锁。锁定超时期限可以限制,这样就可以限制被阻塞的请求在超时之前要等待的时间。
阶段1:事务A请求资源S1,事务不对资源S1进行操作
阶段2:事务A用锁A锁定资源S1,事务B请求对资源S1进行不兼容的锁定(锁B),锁B的请求被阻塞,事务B将进入等待状态
阶段3:事务A正在释放锁A,事务B等待锁A释放,
阶段4:事务A的锁A已释放,事务B用锁B锁定资源S1
2.排除阻塞
例子:
(1)准备工作:
1.准备测试数据
--先创建一张表Product作为测试。id为表的主键,price为product的价格 CREATE TABLE [dbo].[myProduct]( [id] [int] NOT NULL, [price] [money] NOT NULL ) ON [PRIMARY] GO --插入一条数据,id=1,price=10 INSERT INTO [TSQLFundamentals2008].[dbo].[myProduct]([id],[price])VALUES(1,10)
2.模拟阻塞发生的情况
在SQL Server中打开三个查询窗口Connection1、Connection2、Connection3,分别按顺序执行表格中的执行语句。
--Connection1 BEGIN TRAN UPDATE dbo.myProduct SET price = price + 1 WHERE id=1 --Connection2 SELECT * FROM dbo.myProduct WHERE id=1 --Connection3 SELECT request_session_id AS 会话id , resource_type AS 请求锁定的资源类型 , resource_description AS 描述 , request_mode AS 模式 , request_status AS 状态 FROM sys.dm_tran_locks
查询窗口
服务器进程标识符SPID
执行语句
结果 说明Connection1 52
--语句1: BEGIN TRAN UPDATE dbo.myProduct SET price = price + 1 WHERE id=1 更新产品价格10.00->11.00
为了更新id=1这一行数据,会话必须先获得一个排他锁。事务处于一直打开状态,没有提交,所以事务一直持有排他锁,直到事务提交并完成。
Connection2 56
--语句2: SELECT * FROM dbo.myProduct WHERE id=1
事务为了读取数据,需要请求一个共享锁,但是这一行已经被其他会话持有的排他锁锁定,而且共享锁和排他锁不是兼容的,所以会话被阻塞,进入等待状态
Connection3 57
--语句3: SELECT request_session_id AS 会话id , resource_type AS 请求锁定的资源类型 , resource_description AS 描述 , request_mode AS 模式 , request_status AS 状态 FROM sys.dm_tran_locks
会话56:
(1)状态WAIT-等待锁
(2)正在等待第1个数据文件上的第109页上的第0行资源的共享锁
(3)持有第1个数据文件上的第109页资源的意向共享锁
(3)持有OBJECT资源,意向共享锁
(4)持有DATABASE资源,意向共享锁
会话52:
(1)状态WAIT-授予锁
(2)正在等待第1个数据文件上的第109页上的第0行资源的排他锁(3)持有第1个数据文件上的第109页资源的排他锁
(3)持有OBJECT资源,排他锁
(4)持有DATABASE资源,排他锁
(2)分析阻塞
★ 1.sys.dm_tran_locks 视图
(1)该动态视图可以查询出哪些资源被哪个进程ID锁了
(2)查询出对资源授予或正在等待的锁模式
(3)查询出被锁定资源的类型
上面的查询语句3已经用到了这个视图,可以参考上图中的分析说明。
★ 2.sys.dm_exec_connections 视图
(1)查询出该动态视图可以查询出进程相关的信息
(2)查询出最后一次发生读操作和写操作的时间last_read,last_write
(3)查询出进程执行的最后一个SQL批处理的二进制标记most_recent_sql_handle
查询窗口
服务器进程标识符SPID
执行语句
结果 说明Connection3 57
SELECT session_id , connect_time , last_read , last_write , most_recent_sql_handle FROM sys.dm_exec_connections WHERE session_id IN ( 52, 56 )