读取已提交的快照VS快照隔离级别


73

请问有人可以帮助我了解何时在SQL Server中通过READ COMMITTED SNAPSHOT使用SNAPSHOT隔离级别吗?

我了解在大多数情况下,READ COMMITTED SNAPSHOT可以工作,但不确定何时进行SNAPSHOT隔离。

谢谢

Answers:


73

READ COMMITTED SNAPSHOT乐观阅读和悲观写作。相反,SNAPSHOT乐观读和乐观写。

Microsoft建议READ COMMITTED SNAPSHOT大多数需要行版本控制的应用程序。

阅读这篇出色的Microsoft文章:选择基于行版本控制的隔离级别。它说明了两个隔离级别的好处和成本。

这里是更详尽的一个:http : //msdn.microsoft.com/zh-cn/library/ms345124(SQL.90).aspx


5
这似乎是不正确的。请参阅dba.stackexchange.com/a/54681/52708
丹b

乐观读取和乐观写入有什么区别?谷歌搜索无法解释,谢谢,

这是一个尚不了解的术语的答案,没有人甚至不知道乐观读,乐观写,悲观读和悲观写的

乐观和悲观是相当普遍的术语,它们确实具有含义。我看不到发布的链接如何与此答案相矛盾。
约翰·布勒(JohanBoulé)

43

在此处输入图片说明[![隔离级别表] [2]] [2]

请参阅以下示例:

读取提交的快照

如下更改数据库属性

ALTER DATABASE SQLAuthority
SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE
GO

第一场

USE SQLAuthority
GO
BEGIN TRAN
UPDATE DemoTable
SET i = 4
WHERE i = 1

第二场

USE SQLAuthority
GO
BEGIN TRAN
SELECT *
FROM   DemoTable
WHERE i = 1

结果–会话2中的查询显示旧值(1,ONE),因为当前事务未提交。这是避免阻塞和读取已提交数据的方法。

第一场

COMMIT

第二场

USE SQLAuthority
GO
SELECT *
FROM   DemoTable
WHERE i = 1

结果–会话2中的查询未显示任何行,因为该行在会话1中已更新。因此,我们再次看到已提交的数据。

快照隔离级别

这是新的隔离级别,可从SQL Server 2005开始使用。对于此功能,由于必须使用新的隔离级别,因此应用程序需要进行更改。

使用下面的方法更改数据库设置。我们需要确保数据库中没有事务。

ALTER DATABASE SQLAuthority SET AllOW_SNAPSHOT_ISOLATION ON

现在,我们还需要使用以下命令更改连接的隔离级别

第一场

USE SQLAuthority
GO
BEGIN TRAN
UPDATE DemoTable
SET i = 10
WHERE i = 2

第二场

SET TRANSACTION ISOLATION LEVEL SNAPSHOT
GO
USE SQLAuthority
GO
BEGIN TRAN
SELECT *
FROM   DemoTable
WHERE i = 2

结果-即使我们将值更改为10,我们仍将在会话2中看到旧记录(2,两个)。

现在,让我们在会话1中提交事务

第一场

COMMIT

让我们回到会话2并再次运行select。

第二场

SELECT *
FROM   DemoTable
WHERE i = 2

我们仍将看到该记录,因为会话2已使用快照隔离声明了该事务。除非我们完成交易,否则不会看到最新记录。

第二场

COMMIT
SELECT *
FROM   DemoTable
WHERE i = 2

现在,我们不应该看到该行,因为它已经更新。

请参阅:SQL AuthoritySafari联机丛书


4
使用示例,此答案比选择的答案更好。
jyao

1
同意,这是对外部资源的最佳指示的最佳答案。
Sanjiv Jivan

9

如果不讨论可能在快照中发生的可怕的“快照更新冲突”异常,而不对“快照已提交”,则快照和“已提交快照读取”的比较是不完整的。

简而言之,快照隔离在事务开始时检索已提交数据的快照。,然后对读取和写入使用乐观锁定。如果在尝试提交事务时,发现其他更改更改了某些相同的数据,则数据库将回滚整个事务并引发错误,从而导致调用代码中出现快照更新冲突异常。这是因为受事务影响的数据版本在事务结束时与开始时不同。

快照已提交快照不受此问题的困扰,因为它使用了写锁定(悲​​观写),并且在每个语句的stat处获取所有已提交数据的快照版本信息。

快照更新和“未提交快照读取”中发生快照更新冲突的可能性是两者之间的极大差异。


1

仍然相关,从比尔的评论开始,我阅读了更多内容,并做了一些可能对其他人有用的笔记。

默认情况下,单个语句(包括SELECT)对“已提交”的数据(“读已提交”)起作用,问题是:它们是否在等待数据为“空闲”并阻止其他人在读取时工作?

通过右键单击DB“属性->选项->其他”进行设置:

并发/阻止:已提交读快照快照[默认关闭,应该打开]:

  • 使用SNAPSHOT进行选择(读取),不要等待其他人,也不要阻止他们。
  • 无需更改代码即可进行操作
  • ALTER DATABASE <dbName> SET READ_COMMITTED_SNAPSHOT [ON|OFF]
  • SELECT name, is_read_committed_snapshot_on FROM sys.databases

一致性:允许快照隔离[默认关闭,有争议-确定关闭]:

  • 允许客户端跨SQL语句(事务)请求SNAPSHOT。
  • 代码必须请求“交易”快照(如SET TRANSACTION ...
  • ALTER DATABASE <dbName> SET ALLOW_SNAPSHOT_ISOLATION [ON|OFF]
  • SELECT name, snapshot_isolation_state FROM sys.databases

的问题:它不是一个读取提交快照和允许快照隔离的其他。它们是快照的两种情况,并且可以单独打开或关闭,“允许快照隔离”则是高级主题。允许快照隔离允许代码进一步控制快照范围。

如果您考虑一行,问题似乎很明显:默认情况下,系统没有副本,因此,如果有人在写,则读者必须等待,如果有人在阅读,则作家也必须等待–该行必须锁定所有时间。启用“正在读取提交的快照”将激活数据库以支持“快照副本”,以避免这些锁定。

bling ...

我认为,对于任何普通的MS SQLServer数据库,“正在读取已提交的快照”应该为TRUE,并且默认情况下它为FALSE是过早的优化。

但是,我被告知,单行锁会变得更糟,这不仅是因为您可能要处理跨表的多行,而且还因为在SQL Server中,行锁是使用“块”级锁实现的(锁定与存储相关性相关的随机行),并且存在多个锁触发表锁定的阈值-可能是更“乐观”的性能优化,可能会阻塞繁忙数据库中的问题。

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.