TABLOCK
和TABLOCKX
http://msdn.microsoft.com/en-us/library/ms187373.aspx状态之间的区别是TABLOCK
是共享锁,而TABLOCKX
是排他锁。第一个可能只是一个索引锁吗?分享锁的概念是什么?
答案 0 :(得分:93)
差异很大,TABLOCK
将尝试获取“共享”锁,并TABLOCKX
排他锁。
如果您正在进行交易,并且您在桌子上获得了一个独占锁,那么EG:
SELECT 1 FROM TABLE WITH (TABLOCKX)
没有其他进程能够抓取表中的任何锁,这意味着在事务提交之前,阻止尝试与该表通信的所有查询。
TABLOCK
仅获取共享锁,如果事务隔离为READ COMMITTED
(默认),则在执行语句后释放共享锁。如果您的隔离级别is higher,例如:SERIALIZABLE
,则共享锁将保留到事务结束。
共享锁是嗯,共享。这意味着如果两个事务都在表上持有S或IS锁定(通过TABLOCK
),则它们可以同时从表中读取数据。但是,如果transaction A
持有表上的共享锁,transaction B
将无法获取独占锁,直到释放所有共享锁。了解哪些锁与at msdn兼容。
两个提示都会导致数据库绕过更细粒度的锁(如行或页级锁)。原则上,更精细的锁可以让您获得更好的并发性。因此,例如,一个事务可能正在更新表中的第100行,而另一行1000,同时来自两个事务(使用页面锁会变得棘手,但让我们跳过它)。
通常,粒度锁是您想要的,但有时您可能希望减少db并发性以提高特定操作的性能并消除死锁的可能性。
一般情况下,您不会使用TABLOCK
或TABLOCKX
,除非您对某些边缘情况绝对需要它。
答案 1 :(得分:4)
相当旧的article on mssqlcity尝试解释锁的类型:
共享锁用于不更改或更新数据的操作,例如SELECT语句。
当SQL Server打算修改页面时使用更新锁,稍后在实际进行更改之前将更新页锁定提升为独占页锁。
独占锁用于数据修改操作,例如UPDATE,INSERT或DELETE。
它没有讨论的是Intent(它基本上是这些锁类型的修饰符)。意图(共享/独占)锁是保持在比真实锁更高级别的锁。因此,例如,如果您的事务在一行上有X锁定,那么它在表级别也会有一个IX锁定(这会阻止其他事务尝试在表格的更高级别获取不兼容的锁定(例如模式)修改锁定),直到您的交易完成或回滚)。
“共享”锁的概念非常简单 - 多个事务可以对同一资源具有共享锁,而只有一个事务可以具有Exclusive锁,而Exclusive锁可以阻止任何事务获取或持有共享锁。
答案 2 :(得分:2)
这是TABLOCK不能为我和TABLOCKX工作的一个例子。
我有2个会话,它们都使用默认(READ COMMITTED)隔离级别:
会话1是一个显式事务,它将数据从链接服务器复制到数据库中的一组表,并且需要几秒钟才能运行。 [示例,删除问题] 会话2是一个插入语句,它只是将行插入到会话1不进行更改的表中。 [例如,它插入了答案]。
(实际上,有多个会话同时在表中插入多个记录,而会话1正在运行其事务)。
会话1必须查询会话2插入表,因为它无法删除依赖于会话2添加的条目的记录。[示例:删除尚未回答的问题]。
因此,当会话1正在执行且会话2尝试插入时,会话2每次都会陷入死锁。
因此,Session 1中的delete语句可能如下所示: 删除tblA FROM tblQ LEFT JOIN tblX on ... LEFT JOIN tblA a ON tblQ.Qid = tblA.Qid 在哪里...... a.QId是空的......
死锁似乎是由查询tblA之间的争用引起的,而第2节,[3,4,5,...,n]尝试插入到tblA中。
在我的情况下,我可以将Session 1的事务的隔离级别更改为SERIALIZABLE。当我这样做时:事务管理器已禁用其对远程/网络事务的支持。
所以,我可以按照接受的答案中的说明来解决它:The transaction manager has disabled its support for remote/network transactions
但是a)我不习惯首先将隔离级别更改为SERIALIZABLE-据说它会降低性能并可能产生其他后果我没有考虑过,b)不明白为什么这样做会突然导致事务在链接服务器上运行时出现问题,以及c)不知道通过启用网络访问可能会出现哪些漏洞。
在一个非常大的交易中,似乎只有6个查询导致了这个问题。
所以,我读到了TABLOCK和TabLOCKX。
我对这些差异并不十分清楚,也不知道两者是否有效。但它似乎会。首先,我尝试了TABLOCK,它似乎没有任何区别。竞争会话产生了相同的死锁。然后我尝试了TABLOCKX,没有更多的死锁。
所以,在六个地方,我需要做的就是添加一个WITH(TABLOCKX)。
因此,Session 1中的delete语句可能如下所示: 删除tblA FROM tblQ q LEFT JOIN tblX x on ... LEFT JOIN tblA a WITH(TABLOCKX)ON tblQ.Qid = tblA.Qid 在哪里...... a.QId是空的......