快照隔离行为。 "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
不是 Commit
或 Rollback
。
之后,它将从 Table 读取数据。
在@s2中,Begin Tran
没有回滚或者Commit
。
虽然所有记录都在@s1 中提交,
它不获取 3。它获取 1,2,这是 committed
在发布 T Sql 之前在同一个 table.
如果在@S2 中完成回滚或提交,则输出将为 (1,2,3)。
由于@s1 中的所有 Insert 语句都已提交。
在Transaction
为Commit
或Rollback
后,会从.
读取数据
在其他例子中,
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
读取。
在Commit
或Rollback
之后,会再次刷新TempDB
的记录。
所以@s2 中的输出将为 1
我正在做一些测试,试图了解快照隔离的工作原理……但我没有。我的数据库中有 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
.
换句话说,它将为所有 tables in TempDB
mention in T-Sql this TRANSACTION
.
它将从 TempDB
读取数据,直到 Transaction
不是 Commit
或 Rollback
。
之后,它将从 Table 读取数据。
在@s2中,Begin Tran
没有回滚或者Commit
。
虽然所有记录都在@s1 中提交,
它不获取 3。它获取 1,2,这是 committed
在发布 T Sql 之前在同一个 table.
如果在@S2 中完成回滚或提交,则输出将为 (1,2,3)。 由于@s1 中的所有 Insert 语句都已提交。
在Transaction
为Commit
或Rollback
后,会从.
在其他例子中,
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
读取。
在Commit
或Rollback
之后,会再次刷新TempDB
的记录。
所以@s2 中的输出将为 1