【问题标题】:TABLOCK vs TABLOCKXTABLOCK 与 TABLOCKX
【发布时间】:2011-02-24 08:31:47
【问题描述】:

TABLOCKTABLOCKX 有什么区别?

http://msdn.microsoft.com/en-us/library/ms187373.aspx 声明TABLOCK 是共享锁,而TABLOCKX 是排他锁。第一个可能只是某种索引锁吗?共享锁是什么概念?

【问题讨论】:

  • 它指出TABLOCK 是一个共享​​> 锁,允许多个客户端同时将数据加载到表中。排他锁不会。
  • @Lieven 使用 tabblocks 时,互斥性被排除在数据表在保留页内存周期中的锁之外。

标签: sql-server tsql


【解决方案1】:

差别很大,TABLOCK 会尝试抢“共享”锁,而TABLOCKX 会抢独占锁。

如果你在一个事务中并且你在一个表上获取了一个排他锁,例如:

SELECT 1 FROM TABLE WITH (TABLOCKX)

没有其他进程能够获取表上的任何锁,这意味着尝试与表对话的所有查询将被阻止,直到事务提交为止。 p>

TABLOCK 只获取共享锁,如果你的事务隔离为READ COMMITTED(默认),则在执行语句后释放共享锁。如果您的隔离级别为is higher,例如:SERIALIZABLE,则共享锁会一直保持到事务结束。


共享锁是,嗯,共享的。这意味着如果两个事务都持有表上的 S 或 IS 锁(通过TABLOCK),则它们可以同时从表中读取数据。但是,如果transaction A 持有一个表上的共享锁,transaction B 将无法获取独占锁,直到所有共享锁都被释放。了解哪些锁与哪些at msdn 兼容。


这两个提示都会导致数据库绕过获取更细粒度的锁(如行或页级别的锁)。原则上,更细粒度的锁可以让您获得更好的并发性。例如,一个事务可能正在更新表中的第 100 行,而另一个事务可能正在更新表中的第 1000 行,同时来自两个事务(页面锁很棘手,但让我们跳过它)。

通常粒度锁是您想要的,但有时您可能希望降低数据库并发性以提高特定操​​作的性能并消除死锁的机会。

一般情况下,您不会使用 TABLOCKTABLOCKX,除非您在某些极端情况下绝对需要它。

【讨论】:

  • 其中一种极端情况是,例如,您最初创建表并用INSERT INTO 等数据填充它的情况。在这种情况下,独占锁可以为您带来很大的性能提升。
  • 意思是 所有 试图与表 交谈 的查询将被阻止,直到事务提交。这不是真的。您仍然可以使用 NOLOCK 或 TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 进行读取
  • 这似乎不适用于 sql server 2016 ?
【解决方案2】:

相当古老的article on mssqlcity 试图解释锁的类型:

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

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

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

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


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

【讨论】:

  • 持有锁的时间有区别吗? TABLOCK 一直保持到语句结束。如果还指定了 HOLDLOCK,则共享表锁将一直保持到事务结束。但是 TABLOCKX 呢
  • @Carlo - 排他锁始终保持到事务结束。
  • @Carlo,所有共享锁都在读提交事务中的语句结束时释放,如果你想持有你需要提示或更高隔离级别的锁。 tablockx 将获取 X 锁。
【解决方案3】:

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

我有 2 个会话,它们都使用默认(已提交)隔离级别:

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

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

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

因此,当 Session 1 正在执行并且 Session 2 尝试插入时,Session 2 每次都在死锁中失败。

因此,会话 1 中的删除语句可能如下所示: 从 tblQ 中删除 tblA 左连接 tblX on ... 左加入 tblA a ON tblQ.Qid = tblA.Qid WHERE ... a.QId 为 NULL 并且 ...

死锁似乎是由于在 Session 2, [3, 4, 5, ..., n] 尝试插入 tblA 时查询 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)。

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

【讨论】:

  • 欢迎来到stackoverflow!感谢您发布您的第一个答案。我认为如果您删除个人参考资料并保留基本事实,这个答案对其他人会更有用。继续努力!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多