快照隔离行为。 "Triggered" 第一次查询?

Snapshot isolation behaviour. "Triggered" at first query?

我正在做一些测试,试图了解快照隔离的工作原理……但我没有。我的数据库中有 SET ALLOW_SNAPSHOT_ISOLATION ON(对 READ_COMMITTED_SNAPSHOT atm 不感兴趣)。然后我做以下测试。我将通过 [s1] 和 [s2] 标记来标记不同的会话(我的 ssms 中实际上是不同的选项卡),[s2] 是隔离会话,[s1] 模拟另一个非隔离会话。

首先,做一个table,让我们给它排个序。 @[s1]:

create table _g1 (v int)
insert _g1 select 1
select * from _g1
(Output: 1)

现在让我们开始一个孤立的事务。 @[s2]:

set transaction isolation level snapshot
begin tran

插入另一行,@[s1]:

insert _g1 select 2

现在让我们看看孤立的交易是什么"sees",@[s2]:

select * from _g1
(Output: 1,2)

奇怪。隔离 "start counting" 不应该从 "Begin tran" 的那一刻起吗?在这里,它不应该返回 2....让我们再做一次。 @[s1]:

insert _g1 select 3

@[s2]:

select * from _g1
(Output: 1,2)

所以,这次它如我所愿,没有考虑最新的插入。

如何解释这种行为?每个 table 的第一次访问后隔离是否开始工作?

快照隔离适用于行版本控制。对于一行的每次修改,数据库引擎都会维护该行的先前版本和当前版本,以及进行修改的事务的序列号 (XSN)。

当快照隔离用于[s2]中的事务时:

The Database Engine reads a row within the transaction and retrieves the row version from tempdb whose sequence number is closest to, and lower than, the transaction sequence number.

(请参阅 https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/snapshot-isolation-in-sql-server 中的“快照隔离和行版本控制的工作原理”)。在发出 DML 语句之前,不会分配 [s2] 中交易的交易序列号 XSN2。

sys.dm_tran_active_snapshot_database_transactions 是 DMV,returns 是虚拟的 table 对于生成或可能访问行版本的所有活动事务。您可以查询此视图以获取有关访问行版本的活动事务的信息。

要验证以上所有内容,您可以尝试:

@[s1]

create table _g1 (v int)

@[s2]

set transaction isolation level snapshot
begin tran

select * from sys.dm_tran_active_snapshot_database_transactions  -- < No XSN has been assigned, yet. Zero rows are returned.

select * from _g1 --< XSN2 is now assigned.
(Output: zero rows)

select * from sys.dm_tran_active_snapshot_database_transactions  -- < XSN2 has been assigned and the corresponding record is returned.

@[s1]

insert _g1 select 1
select * from _g1
(Output: 1)

@[s2]

select * from _g1
(Output: zero rows)

请参阅 https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-tran-active-snapshot-database-transactions-transact-sql?view=sql-server-ver15 中关于何时发布 XSN 的备注:

sys.dm_tran_active_snapshot_database_transactions reports transactions that are assigned a transaction sequence number (XSN). The XSN is assigned when the transaction first accesses the version store. In a database that is enabled for snapshot isolation or read committed isolation using row versioning, the examples show when an XSN is assigned to a transaction:

  • If a transaction is running under serializable isolation level, an XSN is assigned when the transaction first executes a statement, such as an UPDATE operation, that causes a row version to be created.

  • If a transaction is running under snapshot isolation, an XSN is assigned when any data manipulation language (DML) statement, including a SELECT operation, is executed.

因此,为了回答您的问题,快照隔离在第一个 'SELECT' 或事务中发出的其他 DML 语句之后“开始计数”,而不是在 'begin trasaction' 语句之后立即开始。

你可以Set Transaction Isolation Level Snapshot 在数据库级别或会话级别。

在我们的示例中,我们设置了 Session level。 因此 Isolation Level Snapshot 将仅在声明它的那个会话中起作用。 其次,必须发出T-Sql语句。

在@s2 ,

Set Transaction Isolation Level Snapshot
Begin Tran

这里Transaction是开放的,但是没有T-Sql

那么 Snapshot Version 其中 table 将被维护?

Set Transaction Isolation Level Snapshot
Begin Tran
select * from _g1

此处 isolation level 将适用于 table _g1。或者在 Transaction .

中 T-Sql 中提到的 table

换句话说,它将为所有 tables in TempDB mention in T-Sql this TRANSACTION.

维护自己的记录版本

它将从 TempDB 读取数据,直到 Transaction 不是 CommitRollback。 之后,它将从 Table 读取数据。

在@s2中,Begin Tran没有回滚或者Commit

虽然所有记录都在@s1 中提交, 它不获取 3。它获取 1,2,这是 committed 在发布 T Sql 之前在同一个 table.

如果在@S2 中完成回滚或提交,则输出将为 (1,2,3)。 由于@s1 中的所有 Insert 语句都已提交。

TransactionCommitRollback后,会从.

读取数据

在其他例子中,

Truncate table _g1.

我们先开始@s2,

Set Transaction Isolation Level Snapshot
Begin Tran
select * from _g1

输出:无记录。

此处数据库引擎已为 table _g1 维护自己的版本。 由于_g1中没有记录,所以TempDB为空

在@s1,

insert _g1 select 1
select * from _g1
(Output: 1)

在@s2,

如果你只是 运行

select * from _g1

或者你运行所有脚本

输出仍然是 nothing.Because 我们还没有提交或 rollback 所以它继续从 TempDB 读取。

CommitRollback之后,会再次刷新TempDB的记录。

所以@s2 中的输出将为 1