【问题标题】:Snapshot isolation behaviour. "Triggered" at first query?快照隔离行为。第一次查询时“触发”?
【发布时间】:2020-03-13 13:35:45
【问题描述】:

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

首先,制作一张表格,让我们给它一行。 @[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

现在让我们看看隔离事务“看到”了什么,@[s2]:

select * from _g1
(Output: 1,2)

奇怪。隔离不应该从“Begin tran”那一刻起“开始计数”吗?在这里,它不应该返回 2....让我们再做一次。 @[s1]:

insert _g1 select 3

@[s2]:

select * from _g1
(Output: 1,2)

所以,这次它按我的预期工作,没有考虑最新的插入。

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

【问题讨论】:

    标签: sql sql-server tsql isolation-level snapshot-isolation


    【解决方案1】:

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

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

    数据库引擎读取事务中的一行并检索 tempdb 中序列号最接近的行版本,以及 低于,交易序号。

    (请参阅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,它返回一个虚拟表 对于生成或可能访问行版本的所有活动事务。您可以查询此视图以获取有关访问行版本的活动事务的信息。

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

    @[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)
    

    XSN何时下发请看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的备注:

    sys.dm_tran_active_snapshot_database_transactions 报告分配了事务序列号 (XSN) 的事务。 XSN 是在事务首次访问版本存储时分配的。在使用行版本控制启用快照隔离或读取提交隔离的数据库中,示例显示了何时将 XSN 分配给事务:

    • 如果事务在可序列化隔离级别下运行,则在事务首次执行导致创建行版本的语句(例如 UPDATE 操作)时分配 XSN。

    • 如果事务在快照隔离下运行,则在执行任何数据操作语言 (DML) 语句(包括 SELECT 操作)时都会分配 XSN。

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

    【讨论】:

    • 您最好对原始问题“隔离是否应该从“Begin tran”那一刻起“开始计数”?”添加明确的答案。答:不是。它从SELECTUPDATE开始。
    • 谢谢@Vladimir,我已经根据您的评论更新了我的答案(现在实际上更清楚了!!!)
    【解决方案2】:

    你可以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 将维护哪个表?

    Set Transaction Isolation Level Snapshot
    Begin Tran
    select * from _g1
    

    这里isolation level 将在表_g1 上工作。或者 Transaction 内的 T-Sql 中提到的表。

    换句话说,它将为TempDB 中提到的所有表维护自己的记录版本TRANSACTION

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

    在@s2 中,Begin Tran 没有 RollBack 或 Commit

    虽然所有记录都在@s1中提交, 它不获取 3。它获取 1,2,它们是 committed 在同一张表上发出 T Sql 之前。

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

    TransactionCommitRollback 后,会从. 中读取数据。

    在另一个例子中,

    Truncate table _g1.

    我们先启动@s2

    Set Transaction Isolation Level Snapshot
    Begin Tran
    select * from _g1
    

    输出:没有记录。

    这里的数据库引擎为表_g1 维护了自己的版本。 由于_g1中没有记录,所以TempDB为空。

    在@s1 中,

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

    在@s2 中,

    如果你只是简单地运行

    select * from _g1
    

    或者你运行所有脚本

    输出仍然没有。因为我们还没有提交或rollback所以它继续从TempDB读取。

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

    所以@s2 中的输出将是 1

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-05
      • 2012-12-05
      • 1970-01-01
      • 1970-01-01
      • 2012-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多