有人可以帮助我了解何时在 SQL Server 中使用 SNAPSHOT 隔离级别而不是 READ COMMITTED SNAPSHOT 吗?
我知道在大多数情况下 READ COMMITTED SNAPSHOT 有效,但不确定何时进行 SNAPSHOT 隔离。
谢谢
有人可以帮助我了解何时在 SQL Server 中使用 SNAPSHOT 隔离级别而不是 READ COMMITTED SNAPSHOT 吗?
我知道在大多数情况下 READ COMMITTED SNAPSHOT 有效,但不确定何时进行 SNAPSHOT 隔离。
谢谢
READ COMMITTED SNAPSHOT
做乐观读和悲观写。相反,SNAPSHOT
乐观读取和乐观写入。
Microsoft 建议READ COMMITTED SNAPSHOT
大多数需要行版本控制的应用程序。
阅读这篇出色的 Microsoft 文章:选择基于行版本控制的隔离级别。它解释了两种隔离级别的好处和成本。
这是一个更彻底的:http: //msdn.microsoft.com/en-us/library/ms345124 (SQL.90).aspx
请参见下面的示例:
读取提交的快照
更改数据库属性如下
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 在线图书
如果不讨论在 Snapshot 中可能发生的可怕的“快照更新冲突”异常,而不是 Snapshot Read Committed,那么 Snapshot 和 Snapshot Read Committed 的比较是不完整的。
简而言之,快照隔离在事务开始时检索已提交数据的快照,然后对读取和写入使用乐观锁定。如果在尝试提交事务时,发现其他东西更改了相同的数据,则数据库将回滚整个事务并引发错误,从而导致调用代码中的快照更新冲突异常。这是因为受事务影响的数据版本在事务结束时与开始时不同。
Snapshot Read Committed 不会遇到这个问题,因为它使用写入锁定(悲观写入)并且它在每个语句的 stat 处获取所有已提交数据的快照版本信息。
Snapshot 和 NOT Snapshot Read Committed 中发生快照更新冲突的可能性是两者之间极其显着的区别。
仍然相关,从比尔的评论开始,我阅读了更多内容,并做了一些可能对其他人有用的笔记。
默认情况下,单个语句(包括 SELECT)处理“已提交”数据(READ COMMITTED),问题是:它们是否等待数据“空闲”并在读取时阻止其他人工作?
通过右键单击数据库“属性->选项->杂项”进行设置:
并发/阻塞:是否已提交读取快照打开[默认关闭,应该打开]:
ALTER DATABASE <dbName> SET READ_COMMITTED_SNAPSHOT [ON|OFF]
SELECT name, is_read_committed_snapshot_on FROM sys.databases
一致性:允许快照隔离[默认关闭,有争议 – 确定关闭]:
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 中,行锁是使用“块”级锁(锁定与存储接近度相关联的随机行)实现的,而且存在多个锁触发表锁定的阈值 - 可能是更“乐观”的性能优化,冒着在繁忙数据库中阻塞问题的风险。