Sebastian Meine来自 dba 的回答:
要回答这个问题,我必须绕道而行,所以请耐心等待。如果两个会话对同一资源进行锁定,SQL Server 会检查锁定兼容性映射,并且如果第二个请求与第一个请求不“兼容”,则第二个会话必须等待。共有三种锁类型“S”hared、“U”pdate 和 e“X”clusive。S 锁用于读取资源,X 锁用于写入资源。S 锁相互兼容,X 锁不兼容其他任何东西。U 锁是一种混合体,在某些情况下用于防止死锁。
现在,SQL Server 可以在多个级别上进行锁定:Table、Partition、Page 和 Row。因此,如果会话 1 使用表锁,而会话 2 对表的一行使用不兼容的锁,则这两个锁不在同一个资源上,SQL Server 不会检测到冲突。为了防止这种情况,SQL Server 总是开始在表级别上锁定并沿着层次结构向下工作。现在页锁和行锁的重点是更高的并发性,所以如果一个会话想要写入一行,另一个会话想要写入另一行,它们不应该互相阻塞。如果一个会话除了对一行进行锁定之外,还必须对表进行相同的锁定,那么这种优势就消失了。因此,会话不是在表上获取排他锁 (X),而是请求一个意向排他锁 (IX)。此锁与其他意图锁兼容,但与其他“真实”锁不兼容。所以另一个会话也可以在同一个表上获得一个排他锁。意向排他锁表示会话打算对较低级别的资源进行排他锁。同样的情况发生在页面级别,如果预期的锁是行锁,那么在完成之后,会话在表和其中一个页面上具有 IX 锁,在该页面中的其中一行上具有 X 锁. 这也意味着,您永远不会在行上找到意向锁,因为行是锁层次结构中的最低级别。同样的情况发生在页面级别,如果预期的锁是行锁,那么在完成之后,会话在表和其中一个页面上具有 IX 锁,在该页面中的其中一行上具有 X 锁. 这也意味着,您永远不会在行上找到意向锁,因为行是锁层次结构中的最低级别。同样的情况发生在页面级别,如果预期的锁是行锁,那么在完成之后,会话在表和其中一个页面上具有 IX 锁,在该页面中的其中一行上具有 X 锁. 这也意味着,您永远不会在行上找到意向锁,因为行是锁层次结构中的最低级别。
在某些情况下,会话持有表或页面上的 S 锁。如果会话现在(在同一个事务中)请求对同一个表中的行进行 X 锁,它首先必须在表/页上获取 IX 锁。但是,会话只能对任何给定资源持有一个锁。因此,要获取 IX 锁,它必须释放 S 锁,这可能是不希望的,因此 SQL Server 提供了一个组合:SIX。
您拥有页面锁定的原因是由于 SQL Server 有时决定锁定页面而不是锁定每一行会更好。如果 al 会话之间已经有很多锁,这种情况经常发生,但也可能有许多其他原因。
理论到此为止。
现在,在您的情况下,六锁由三表连接选择查询持有。除非您明确告诉它(例如使用 XLOCK 提示),否则 select 永远不会采用任何类型的非共享锁。这样的提示在输入缓冲区中不可见,因此我假设 IX 部分是此连接上最后一批的剩余部分。如果您正在使用连接池并且忘记清理所有打开的事务,那么这样的锁可能会永远存在。但它也变得非常难以排除故障。
您可以先运行一个将 OPEN TRAN 与 COMMIT 配对的 XEvent 会话,然后看看您是否可以通过这种方式找到罪魁祸首。
资料来源:https ://dba.stackexchange.com/questions/45284/understanding-six-lock-in-microsoft-sql-server