TABLOCK与TABLOCKX

Car*_*ngo 70 t-sql sql-server

有什么区别TABLOCKTABLOCKX http://msdn.microsoft.com/en-us/library/ms187373.aspx状态TABLOCK是共享锁,TABLOCKX而是独占锁.第一个可能只是一个索引锁吗?共享锁的概念是什么?

Sam*_*ron 95

差异很大,TABLOCK会尝试抓住"共享"锁和TABLOCKX独占锁.

如果您在交易中并且在桌面上获得了独占锁定,则EG:

SELECT 1 FROM TABLE WITH (TABLOCKX)

没有其他进程能够获取表上的任何锁,这意味着在事务提交之前,所有尝试与表通信的查询都将被阻止.

TABLOCK只有抓取共享锁,如果事务隔离是READ COMMITTED(默认),则在执行语句后释放共享锁.如果隔离级别较高,例如:SERIALIZABLE,则共享锁将保留到事务结束.


共享锁是嗯,共享.意思是如果两个事务都在表(via TABLOCK)上持有S或IS锁定,则它们可以同时从表中读取数据.但是,如果transaction A在表上持有共享锁,transaction B则在释放所有共享锁之前将无法获取独占锁.了解哪些锁与msdn兼容哪些锁.


这两个提示都会导致db绕过更精细的锁(如行或页级锁).原则上,更精细的锁可以让您获得更好的并发性.因此,例如,一个事务可能是更新表中的第100行和另一行1000,同时来自两个事务(使用页锁会变得棘手,但让我们跳过它).

通常,粒度锁是您想要的,但有时您可能希望减少db并发性以提高特定操​​作的性能并消除死锁的可能性.

一般情况下你不会使用TABLOCKTABLOCKX除非你绝对需要一些边缘情况.

  • 例如,其中一个边缘情况是,您最初创建表并使用"INSERT INTO"填充数据.在这种情况下,独占锁可以为您带来巨大的性能提升. (7认同)

Dam*_*ver 5

一篇关于 mssqlcity的旧文章试图解释锁的类型:

共享锁用于不更改或更新数据的操作,例如 SELECT 语句。

当 SQL Server 打算修改页面时使用更新锁,然后在实际进行更改之前将更新页面锁提升为独占页面锁。

排他锁用于数据修改操作,例如 UPDATE、INSERT 或 DELETE。

它没有讨论的是 Intent(它基本上是这些锁类型的修饰符)。意图(共享/独占)锁是比实际锁更高级别的锁。因此,例如,如果您的事务在一行上有一个 X 锁,它也会在表级别有一个 IX 锁(这会阻止其他事务尝试在表的更高级别(例如模式)获取不兼容的锁修改锁)直到您的事务完成或回滚)。


“共享”锁的概念非常简单——多个事务可以对同一资源拥有共享锁,而只有单个事务可能拥有排他锁,而排他锁阻止任何事务获取或持有共享锁。


小智 5

这更像是一个 TABLOCK 对我不起作用而 TABLOCKX 对我起作用的例子。

我有 2 个会话,它们都使用默认的(READ COMMITTED)隔离级别:

会话 1 是一个显式事务,它将数据从链接服务器复制到数据库中的一组表,并且需要几秒钟的时间来运行。[例如,它删除问题] 会话 2 是一个插入语句,它只是将行插入会话 1 未对其进行更改的表中。[例如,它插入答案]。

(实际上,当会话 1 运行其事务时,有多个会话同时将多条记录插入表中)。

会话 1 必须查询会话 2 插入的表,因为它无法删除依赖于会话 2 添加的条目的记录。[示例:删除尚未回答的问题]。

因此,当会话 1 正在执行并且会话 2 尝试插入时,会话 2 每次都会陷入死锁。

因此,会话 1 中的删除语句可能如下所示: DELETE tblA FROM tblQ LEFT JOIN tblX on ... LEFT JOIN tblA a ON tblQ.Qid = tblA.Qid WHERE ... a.QId IS NULL and ...

死锁似乎是由于会话 2, [3, 4, 5, ..., n] 尝试插入 tblA 时查询 tblA 之间的争用引起的。

就我而言,我可以将会话 1 的事务的隔离级别更改为可串行化。当我这样做时:事务管理器已禁用其对远程/网络事务的支持。

因此,我可以按照此处接受的答案中的说明来解决它:事务管理器已禁用其对远程/网络事务的支持

但是a)我一开始就不愿意将隔离级别更改为SERIALIZABLE - 据说它会降低性能并且可能会产生我没有考虑到的其他后果,b)不明白为什么这样做会突然导致事务发生跨链接服务器工作的问题,并且 c) 不知道通过启用网络访问可能会打开哪些漏洞。

一个非常大的事务中似乎只有 6 个查询导致了问题。

因此,我阅读了有关 TABLOCK 和 TabLOCKX 的内容。

我不太清楚其中的差异,也不知道两者是否有效。但看起来好像会的。首先我尝试了TABLOCK,它似乎没有任何区别。竞争的会话产生了相同的僵局。然后我尝试了 TABLOCKX,没有再出现死锁。

因此,在六个地方,我所需要做的就是添加一个WITH (TABLOCKX)。

因此,会话 1 中的删除语句可能如下所示: DELETE tblA FROM tblQ q LEFT JOIN tblX x on ... LEFT JOIN tblA a WITH (TABLOCKX) ON tblQ.Qid = tblA.Qid WHERE ... a.QId为空并且...

  • 欢迎来到 stackoverflow!感谢您发布您的第一个答案。我认为如果您删除个人参考并保留基本事实,这个答案对其他人会更有用。保持良好的工作! (3认同)