请问有人可以帮助我理解在 SQL Server 中何时使用快照隔离级别而不是读提交的快照隔离级别吗?
我明白大多数情况下读提交的快照隔离级别可用,但不确定何时应该选择快照隔离级别。
谢谢
请问有人可以帮助我理解在 SQL Server 中何时使用快照隔离级别而不是读提交的快照隔离级别吗?
我明白大多数情况下读提交的快照隔离级别可用,但不确定何时应该选择快照隔离级别。
谢谢
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
第二节课
USE SQLAuthority
GO
BEGIN TRAN
SELECT *
FROM DemoTable
WHERE i = 1
结果 - 会话2中的查询显示旧值(1, ONE),因为当前事务尚未提交。这是避免阻塞和读取已提交数据的方法。
会话1
COMMIT
第二节课程
USE SQLAuthority
GO
SELECT *
FROM DemoTable
WHERE i = 1
结果 - Session 2 的查询未显示任何行,因为该行已在 Session 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
第二节课程
SET TRANSACTION ISOLATION LEVEL SNAPSHOT
GO
USE SQLAuthority
GO
BEGIN TRAN
SELECT *
FROM DemoTable
WHERE i = 2
结果- 即使我们将值更改为10,仍然会在会话2(2,TWO)中看到旧记录。
现在,让我们在会话1中提交事务。
会话1
COMMIT
让我们回到第二个会话并再次运行select语句。
第二个会话
SELECT *
FROM DemoTable
WHERE i = 2
由于Session 2已经使用快照隔离启动了事务,因此我们仍将看到该记录。除非我们完成事务,否则我们将无法看到最新的记录。
Session 2
COMMIT
SELECT *
FROM DemoTable
WHERE i = 2
现在,由于该行已经被更新,因此我们不应该再看到该行。
这份笔记是关于IT技术的,从Bill的评论开始阅读后,我做了些笔记,可能对别人有用。
默认情况下,单个语句(包括SELECT)使用“已提交”数据(READ COMMITTED),问题是:在读取时它们等待数据处于“空闲”状态并停止其他工作吗?
通过右键单击数据库“属性->选项->杂项”进行设置:
并发/阻止:是否开启读取已提交时的快照 [默认关闭,应该开启]:
ALTER DATABASE <dbName> SET READ_COMMITTED_SNAPSHOT [ON|OFF]
SELECT name, is_read_committed_snapshot_on FROM sys.databases
一致性:允许快照隔离 [默认关闭,存在争议 - 关闭OK]:
SET TRANSACTION ...
)ALTER DATABASE <dbName> SET ALLOW_SNAPSHOT_ISOLATION [ON|OFF]
SELECT name, snapshot_isolation_state FROM sys.databases
对于这个问题:Read Committed Snapshot和Allow Snapshot Isolation并不是一种选择,它们都是快照的两种情况,可以独立开启或关闭其中的任何一种。Allow Snapshot Isolation更为高级。它允许代码进入控制快照领域的下一步。
如果你想到一个行的问题,那么这个问题似乎就很清楚了:默认情况下,系统没有副本,因此读者必须等待任何其他人写入,而写者在任何其他人正在读取时也必须等待-该行必须始终锁定。启用“Is Read Committed Snapshot On”将激活DB以支持“快照副本”,以避免这些锁定。
废话连篇...
我认为,对于任何普通的MS SQL Server数据库,“Is Read Committed Snapshot On”应该为TRUE,并且默认情况下设置为FALSE是一种过早的优化。
然而,我被告知,一行锁不仅变得更糟,因为您可能正在处理跨表的多行,而且在SQL Server中,行锁使用“块”级锁来实现(锁定由存储位置相关的随机行),而且有一个阈值,多个锁会触发表锁-可能会导致繁忙数据库中出现阻塞问题的更“乐观”的性能优化。
让我描述两个尚未提及的要点。
首先,让我们明确如何使用这两个因为它们并不直观。
SNAPSHOT 和 READ_COMMITTED_SNAPSHOT 是两种不同的隔离级别。
SNAPSHOT 是你可以像通常一样在事务中显式使用的隔离级别:
begin transaction
set transaction isolation level snapshot;
-- ...
commit
alert database ... set read_committed_snapshot on;
begin transaction
set transaction isolation level read committed;
-- ...
commit
打开此选项后,所有的READ_COMMITTED事务将在READ_COMMITTED_SNAPSHOT隔离级别下运行。这是自动发生的,会影响到所有针对设置为ON的数据库发出的READ_COMMITTED事务。无法以READ_COMMITTED隔离级别运行事务,因为所有使用该级别的事务都会自动转换为READ_COMMITTED_SNAPSHOT。
其次,你不应盲目地使用READ_COMMITTED_SNAPSHOT选项。
为了说明它可能带来的问题,想象一下你有一个简单的事件表,就像这样:
create table Events (
id int not null identity(1, 1) primary key,
name nvarchar(450) not null
-- ...
)
begin transaction
set transaction isolation level read committed; -- automatically set to read committed snapshot when this setting is ON on database level
select top 100 * from Events where id > ${lastId} order by id asc;
commit
begin transaction
insert into Events (name) values ('test 1');
waitfor delay '00:00:10'
commit
...接下来是正常插入:
insert into Events (name) values ('test 2');
在10秒内调用的轮询函数将返回id为2的单行记录。
在更新lastId后进行的下一次轮询将返回空。id为1的行将在10秒后出现。
id为1的事件将被有效跳过。
如果使用带有READ_COMMITTED_SNAPSHOT自动提升选项的READ_COMMITTED模式,将不会发生这种情况。
值得理解这种情景。这与IDENTITY列不保证唯一性无关。这与IDENTITY列不保证严格单调性无关。即使既不违反唯一性也不违反严格单调性,仍然可能出现间隙 - 在看到较低id的提交之前,可能会先看到较高id的提交。
在READ_COMMITTED模式下,不存在这个问题。
在READ_COMMITTED模式下,您也可以看到间隙 - 即回滚的事务。但这些间隙是永久的 - 也就是说,您不会因为事件不会重新出现而跳过它们。即在看到较高id后,您不会再看到较低id重新出现。
在启用READ_COMMITTED_SNAPSHOT之前,请理解上述问题及其影响。
这个选项的控制权属于开发人员与数据库管理员责任之间的灰色地带。如果你是管理员,不应该盲目使用它,因为开发人员在开发应用程序时可能依赖于READ_COMMITTED隔离语义,而打开READ_COMMITTED_SNAPSHOT可能会违反这些假设,导致非常隐晦、难以找到的错误。