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

时间:2010-04-29 21:48:54

标签: sql-server snapshot isolation-level read-committed-snapshot

有人可以帮我理解何时使用SNAPSHOT隔离级别而不是SQL Server中的READ COMMITTED SNAPSHOT?

据我所知,在大多数情况下,READ COMMITTED SNAPSHOT可以正常工作,但不确定何时进行SNAPSHOT隔离。

由于

4 个答案:

答案 0 :(得分:70)

READ COMMITTED SNAPSHOT执行乐观的阅读和悲观的写作。相比之下,SNAPSHOT执行乐观读取和乐观写入。

对于大多数需要进行行版本控制的应用,Microsoft建议使用READ COMMITTED SNAPSHOT

阅读这篇优秀的微软文章:Choosing Row Versioning-based Isolation Levels。它解释了两种隔离级别的好处和成本。

这是一个更彻底的: http://msdn.microsoft.com/en-us/library/ms345124(SQL.90).aspx

答案 1 :(得分:30)

enter image description here [![隔离级别表] [2]] [2]

请参阅以下示例:

读取提交的快照

更改数据库属性,如下所示

ALTER DATABASE SQLAuthority
SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE
GO

第1节

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

第2节

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

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

第1节

COMMIT

第2节

USE SQLAuthority
GO
SELECT *
FROM   DemoTable
WHERE i = 1

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

快照隔离级别

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

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

ALTER DATABASE SQLAuthority SET AllOW_SNAPSHOT_ISOLATION ON

现在,我们还需要使用下面的

来更改连接的隔离级别

第1节

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

第2节

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

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

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

第1节

COMMIT

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

第2节

SELECT *
FROM   DemoTable
WHERE i = 2

我们仍然会看到记录,因为会话2已经说明了具有快照隔离的事务。除非我们完成交易,否则我们不会看到最新的记录。

第2节

COMMIT
SELECT *
FROM   DemoTable
WHERE i = 2

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

请参阅:SQL AuthoritySafari Books Online

答案 2 :(得分:3)

在没有讨论可怕的快照更新冲突的情况下,没有快照和快照读取提交的比较完成。快照中可能发生的异常,但快照读取已提交。

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

Snapshot Read Committed不会遇到此问题,因为它使用写入锁定(悲观写入),并在每个语句的统计信息中获取所有已提交数据的快照版本信息。

快照和非快照读取提交中发生快照更新冲突的可能性是两者之间极为显着的差异。

答案 3 :(得分:0)

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

默认情况下,单个语句(包括“SELECT”)处理“已提交”数据(READ COMMITTED),问题是:他们是否等待数据“空闲”并在阅读时阻止其他人工作?

通过右键单击DB设置“属性 - >选项 - >杂”:

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

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

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

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

问题:在Read Committed Snapshot和Allow Snapshot Isolation之间不是另一个。它们是两种快照,并且可以单独打开或关闭,允许快照隔离更多是高级主题。允许快照隔离允许代码更进一步控制Snapshot land。

如果您考虑一行,问题似乎很清楚:默认情况下,系统没有副本,因此读者必须等待其他人正在写作,并且作者还必须等待其他人正在阅读 - 行必须一直锁定。启用“读取已提交的快照”会激活数据库以支持“快照副本”以避免这些锁定。

漫步......

在我看来,对于任何普通的MS SQLServer数据库,“Read Committed Snapshot On”都应为“TRUE”,并且默认情况下它是“FALSE”的过早优化。

但是,我被告知一行锁变得更糟,不仅因为你可能在表中寻址多行,而且因为在SQL Server中使用“块”级锁实现行锁(锁定由存储邻近关联的随机行)并且存在一个阈值,其中多个锁触发表锁定 - 可能是更“乐观”的性能优化,存在阻塞繁忙数据库中的问题的风险。