锁定提示只是提示。不能“强制”SQL使用特定类型的锁。
select tl.request_session_id,
tl.resource_type,
tl.request_mode,
tl.resource_description,
tl.request_status
from sys.dm_tran_locks tl
join sys.partitions pt on pt.hobt_id = tl.resource_associated_entity_id
join sys.objects ob on ob.object_id = pt.object_id
where tl.resource_database_id = db_id()
order by tl.request_session_id
create table t(i int, j int);
insert t values (1, 1), (2, 2);
begin tran;
update t with(rowlock) set j = 2 where i = 1;
打开第二个SSMS窗口,运行以下命令:
begin tran;
update t with(rowlock) set j = 2 where i = 2;
第二次执行将被阻止。为什么?
在第三个窗口中运行锁定查询,注意有两行带有
resource_type
属于
RID
,一个有一个
status
地位
“等等”。我们会去的
摆脱
resource_description
这些行的列。它的价值是一样的。
好的,那么什么是
? 这取决于天气
资源类型
. 但对于我们的
摆脱
i = 1
. 当它扫描时,每行上都会有一个更新锁。为什么每行都需要一个更新锁?嗯,可以说,这不是“做”更新。这需要一个专用锁。更新锁通常是用来防止死锁的。
U
锁定每一行。当然,它在插槽0中找到了要立即更新的行,并进行了一次修改
X
十
然后我们开始第二个查询,它还必须扫描所有的行以找到它想要的行。一开始是想抢占先机
U
十
我们第一个查询的锁正在阻止它。
因此,您可以看到,即使使用行锁定,您的第二个查询仍然被阻塞。
i
,获取其独占锁,并等待我们提交。
查询2出现,获取插槽0上的更新锁,查看它想要的值,获取它的独占锁,更新值,
,因为这可能也有它想要的价值。
您还将在下一个“级别”上看到“意向锁”,即页面。该操作让引擎的其余部分知道它可能希望在将来某个时候将锁升级到页面级别。但这不是一个因素。页面锁定不是问题的根源。
这种情况下的解决方案?在列上添加索引
. 在这种情况下,这可能是主键。然后可以按任意顺序进行更新。在这种情况下请求行锁定没有区别,因为SQL不知道有多少行与谓词匹配。但即使你试着
力
行锁在某些情况下,即使使用主键或适当的索引,SQL仍然可以选择升级锁类型,因为锁定整个页面或整个表比锁定和解锁单个行更有效。