为什么乐观锁定比悲观锁定快?


9

两种形式的锁定都会导致一个进程等待记录的正确副本(如果该记录当前正被另一个进程使用)。使用悲观锁定,锁定机制来自数据库本身(本机锁定对象),而使用乐观锁定,锁定机制是某种形式的行版本控制,例如时间戳,用于检查记录是否“陈旧”。

但是,两者都会导致第二个进程挂起。所以我问:为什么乐观锁定通常比悲观锁定快/优?并且,在某些用例中,悲观胜于乐观吗?提前致谢!


5
命名中存在非常简短的解释。当发生冲突的锁定的可能性较低时,乐观锁定效果很好。我们对多个流程之间的相互作用感到乐观。当发生冲突的锁定的可能性很高时,悲观锁定效果很好。我们对多个流程之间的相互作用感到悲观。两者都将在次优的情况下表现最佳。
Mark Storey-Smith

乐观锁定可能比悲观锁定快,也可能不会比悲观锁定快,具体取决于您的工作量。
AK

Answers:


8

重复的问题来自:

/programming/129329/optimistic-vs-pessimistic-locking

从以上链接复制/粘贴答案:

乐观锁定是一种策略,您可以在读取记录,记下版本号并在写回记录之前检查版本是否未更改。当您写回记录时,您将过滤版本更新以确保它是原子的。(即,在您检查版本并将记录写入磁盘之间,尚未进行更新)和一次单击即可更新版本。

如果记录脏了(即与您的版本不同),则中止事务,用户可以重新启动它。

此策略最适用于不一定要为会话保留与数据库的连接的大容量系统和三层体系结构。在这种情况下,客户端实际上无法维护数据库锁定,因为连接是从池中获取的,并且您可能不会在从一个访问到另一个访问的访问中使用相同的连接。

悲观锁定是指您锁定记录以供独占使用,直到完成记录为止。它具有比乐观锁定更好的完整性,但是需要您谨慎设计应用程序,以避免死锁。要使用悲观锁定,您需要直接连接到数据库(在两层客户端服务器应用程序中通常是这种情况)或可以独立于连接使用的外部可用事务ID。

在后一种情况下,您可以使用TxID打开事务,然后使用该ID重新连接。DBMS保持锁定状态,并允许您通过TxID备份会话。这就是使用两阶段提交协议(例如XA或COM +事务)的分布式事务的工作方式。

编辑(添加更多信息以解决性能问题):

在性能方面,它取决于您的环境。考虑以下因素来决定:

在大多数情况下,由于并发性,您会发现乐观会更好。但是,取决于RDBMS和环境,该性能可能会更低或更高。通常,使用乐观锁定,您会发现该值需要在某处进行行版本控制。

例如,使用MS SQL Server,它将移至TempDB,并在该列的末尾附加12-14字节之间的内容。使用隔离级别(例如快照隔离)打开乐观锁定可能会导致碎片,并且您需要调整填充因子,因为行现在在末尾有其他数据,这可能会导致页面接近满而导致页面拆分,从而降低页面使用率你的表现。如果您的TempDB未得到优化,那么速度将不会很快。

所以我想一个清单是:

  • -您是否有足够的IO /资源来处理行版本控制的形式?否则,您将增加开销。如果是这样,那么如果您经常在锁定写入数据的同时经常读取数据,则会发现读写之间的并发性有了很大的改善(尽管写入仍然会阻塞写入,读取将不再阻塞写入,反之亦然)
  • -您的代码容易出现死锁还是遇到锁定?如果您没有遇到长锁或大量死锁,那么乐观锁的额外开销不会使事情变得更快,当然,在大多数情况下,我们在这里说的是毫秒。
  • -如果您的数据库很大(或在非常有限的硬件上)并且您的数据页几乎已满,则取决于RDBMS,您可能会导致主要的页面拆分和数据碎片,因此请确保在打开它之后考虑重新索引。

这些是我对此事的想法,欢迎社会各界听取。


感谢@Ali Razeghi(+1)-我认为dba.se是解决此问题的更合适的地方。另外,尽管这是一个很棒的答案,但它并不能回答我的性能问题(当一个比另一个更快时)。再次感谢!
2013年

嗨,马拉,这很不错。我扩大了答案。谢谢。
Ali Razeghi 2013年

11

您误解了乐观锁定。

乐观锁定不会导致事务彼此等待。

乐观锁定可能会导致事务失败,但是这样做不会导致任何“锁定”。如果由于乐观锁定而导致事务失败,则要求用户重新开始。“乐观”一词正是出于这样的期望:导致交易因该原因而失败的条件只会非常例外地出现。“乐观”锁定是一种方法,它表示“我不会使用实际的锁定,因为我希望无论如何都不需要它们。如果事实证明我错了,那我将接受不可避免的失败。”


1

乐观锁定通常更快,因为从数据库的角度来看实际上没有锁定。是否尊重版本列(或不支持伪列,如ora_rowscn)完全取决于应用程序。通常,您有许多应用程序连接到同一数据库,因此db成为共享资源,如果挂起,则所有客户端都会受到影响。

使用乐观锁定策略,“挂起”发生在客户端,不会影响其他客户端。

但是,如果记录经常更新,您可能最终会重新读取该记录太多次(在乐观锁定的情况下),从而失去了乐观策略的最大好处。

我不同意这两种方法的优越性。它们都可能被滥用。悲观主义更容易出错,因为它更危险:锁定发生在数据库级别,取决于RDMS,您可能无法控制锁定的内容(锁定升级),您需要手动处理锁定顺序。


有趣的是a1ex07,但是乐观锁定仍然包括锁定,因为写入将始终阻止其他写入,对吗?
Ali Razeghi 2013年

不,不是。这就是为什么它“更快”。
Erwin Smout,2013年

对于Oracle,对于MS SQL Server可能就是这种情况,因为默认情况下它使用“读取已提交”隔离级别,因此乐观锁定将允许读取器和写入器线程同时工作,但是写入将阻止写入,直到阻塞线程提交为止。
Ali Razeghi 2013年

@Ali Razeghi:我不确定我是否遵循你的观点。在具有已读提交作者的SQLServer中,默认情况下会阻止读者,除非已打开READ_COMMITTED_SNAPSHOT。乐观锁定不是对数据库资源(行/页/表)的锁定,而是所有使用数据库不更新记录的应用程序之间的某种协议(如果版本与预期不符)。
2013年

1
@Eamon Nerbonne:我说过“作家不阻止读者” ...您在哪里看到我提到过“作家阻止/不阻止作家”?
13年

0

乐观锁定假定并发事务可以完成而不会互相影响。因此,乐观锁更快,因为在执行事务时不会强制执行锁。这是防止引起并发问题的预防措施。该事务仅验证(三种方式数据集,时间戳记数据类型,检查新旧值)该数据是否没有其他事务修改过该数据。在修改的情况下,事务将回滚。

悲观锁定假定并发事务会相互冲突,因此需要锁定,这是通过指定事务管理的ISOLATION级别(读取未提交,读取已提交,可重复读取和可序列化)来完成的,它通过获取锁定来解决并发问题。锁用于保护共享资源或对象(表,数据行,数据块,缓存项,连接和整个系统)。我们有多种类型的锁,例如共享锁,更新锁,插入锁,排他锁,事务锁,DML锁,架构锁和备份-恢复锁。

得到更多的想法


-3

说悲观的锁定比乐观的慢而不是乐观的,或者说乐观的锁定更快是错误的。展示这种不恰当思维方式的一个经典查询是对不同的RDBMS进行汇总,例如:

SELECT COUNT(*) FROM atable

您将看到,在支持本机乐观方法的RDBMS中,此查询所花费的时间比拥有本机悲观锁的人花费的时间要多得多。

例如在我的PC上,同一查询在SQL Server上花费27毫秒,在PostGreSQL上花费109 ...

读取MVCC行的失效版本并且不计算总计中的虚假记录所需的额外开销增加了悲观主义者没有的额外成本!


4
DBMS并发控制方法与乐观/悲观锁定正交,并且在两个不同的DBMS中比较查询运行时间具有误导性。
mustaccio

因为SQL Server能够执行两种锁定模式,所以您可以通过在用户并发方法中执行真正的becnhmark来轻松比较这两种锁定模式。
user7370003
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.