76

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

我知道在大多数情况下 READ COMMITTED SNAPSHOT 有效,但不确定何时进行 SNAPSHOT 隔离。

谢谢

4

4 回答 4

77

READ COMMITTED SNAPSHOT做乐观读和悲观写。相反,SNAPSHOT乐观读取和乐观写入。

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

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

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

于 2010-05-06T06:43:44.647 回答
52

在此处输入图像描述[![隔离等级表][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 权威Safari 在线图书

于 2016-03-29T21:34:41.400 回答
11

如果不讨论在 Snapshot 中可能发生的可怕的“快照更新冲突”异常,而不是 Snapshot Read Committed,那么 Snapshot 和 Snapshot Read Committed 的比较是不完整的。

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

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

Snapshot 和 NOT Snapshot Read Committed 中发生快照更新冲突的可能性是两者之间极其显着的区别。

于 2018-01-25T22:41:07.187 回答
2

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

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

通过右键单击数据库“属性->选项->杂项”进行设置:

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

  • 使用 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

对于这个问题:读取提交的快照和允许快照隔离之间不是一个或另一个。它们是 Snapshot 的两种情况,可以独立打开或关闭,其中 Allow Snapshot Isolation 是一个高级主题。Allow Snapshot Isolation 允许代码进一步控制 Snapshot 区域。

如果你考虑一行,这个问题似乎很清楚:默认情况下,系统没有副本,所以如果其他人正在写入,读取器必须等待,如果其他人正在读取,写入器也必须等待 - 该行必须锁定所有时间。启用“Is Read Committed Snapshot On”会激活数据库以支持“快照副本”以避免这些锁定。

乱跑...

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

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

于 2016-07-15T16:59:10.173 回答