sql server行版本控制的隔离级别

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介:

 在SQL Server标准的已提交读(READ COMMITTED)隔离级别下,一个读操作会和一个写操作相互阻塞。未提交读(READ UNCOMMITTED)虽然不会有这种阻塞,但是读操作可能会读到脏数据,这是大部分用户不能接受的。有些关系型数据库(例如Oracle)使用的是另一种处理方式。在任何一个修改之前,先对修改前的版本做一个复制[WX1] ,后续的一切读操作都会去读这个复制的版本,修改将创建一个新的版本。在这种处理方式下,读、写操作不会相互阻塞。使用这种行版本控制机制的好处,是程序的并发性比较高,但是缺点是用户读到的虽然不是一个脏数据,但是可能是个正在被修改马上就要过期的数据值[WX2] 。如果根据这个过期的值做数据修改,会产生逻辑错误。


 [WX1]复制的内容保存在tempdb当中。

 [WX2]假如读跟写同时进行,读到的不是现在正被修改的值,如果是读到正被修改的值那就是脏读了。读到的是修改前的值。但是这个值随时会过期。等到修改完就过期了。

有些用户可能为了更高的并发性而不在乎这种缺点,所以更喜欢Oracle的那种处理方法。为了满足这部分用户的需求,SQL Server 2005也引入了这种机制,来实现类似的功能。所以选取行版本控制隔离级别也可以成为消除阻塞和死锁的一种手段。

SQL Server有两种行版本控制,使用行版本控制的已提交读隔离(READ_COMMITTED_SNAPSHOT)和直接使用SNAPSHOT事务隔离级别。

  • READ_COMMITTED_SNAPSHOT数据库选项为ON时,READ_COMMITTED事务通过使用行版本控制提供语句级读取一致性。
  • ALLOW_SNAPSHOT_ISOLATION数据库选项为ON时,SNAPSHOT事务通过使用行版本控制提供事务级读取一致性。

下列示例可以说明使用普通已提交读事务,行版本控制的快照隔离事务和行版本控制的已提交读事务的行为差异。

实验1:Read Committed Isolation level

query1:事务1

View Code

query2:事务2

View Code

总结:

  1. 事务1中的读操作没有阻塞事务2中的写操作
  2. 事务2中的更新操作阻塞了事务1中后来的读操作,如下图所示:
  3. 事务1两次查询得到的数据分别是48跟40,两次获得的数据内容不一样。所以也成read committed为不可重复读。在read committed隔离级别中,只在语句级别加锁,当语句执行完以后自动释放锁。比如事务1中的第一次查询,虽然查询在事务中进行,并且事务没有提交,但是此时查询语句执行完以后在table上就找不到锁了。

实验2:Snapshot Isolation

此示例中,在快照隔离下运行的事务将读取数据,然后由另一事务修改此数据。快照事务不会被其他事务执行的更新操作所阻塞,它忽略数据的修改继续从版本化的行读取数据。也就是说,读取到的是数据修改前的版本。但是,当快照事务尝试修改已由其他事务修改的数据时,它将生成错误并终止。

query1:事务1,快照事务

View Code

query2:事务2

View Code

总结:

  1. 快照事务1的读操作没有阻塞普通事务2的读操作,但是阻塞了事务2的删除操作,如果在事务2中执行delete操作的话会报错:Employees cannot be deleted. They can only be marked as not current.Msg 3609, Level 16, State 1, Line 1The transaction ended in the trigger. The batch has been aborted.
  2. 普通事务2的更新操作,没有阻塞事务1的读操作,但是我们发现事务1中读到数据是事务2更新之前的内容。因为读取的是版本化中的行数据。

在上述实验中,我们发现下面两条语句使一起使用的,也就是首先允许数据库开启snapshot isolation,然后再将isolation level设定为snapshot。

复制代码
--step1:启用快照隔离
ALTER DATABASE AdventureWorks
    SET ALLOW_SNAPSHOT_ISOLATION ON;
GO

--step2:设置使用快照隔离级别,前面没有设定是因为数据库默认的隔离界别就是Read Committed
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
GO
复制代码

在执行完step1以前,我们可以在sys.databases中查看AdvantureWorks的snapshot_isolation_state和 is_read_committed_snapshot_on这两个属性:

SELECT name,snapshot_isolation_state, snapshot_isolation_state_desc, is_read_committed_snapshot_on 
FROM sys.databases where name='AdventureWorks';

查询结果如下图所示:

假如我们不执行step1,只执行step2,然后开启事务进行查询,会报如下错误:

Msg 3952, Level 16, State 1, Line 3
Snapshot isolation transaction failed accessing database 'AdventureWorks' because snapshot isolation is not allowed in this database. Use ALTER DATABASE to allow snapshot isolation.

执行完step1以后,我们再次查看sys.databases中的内容,发现snapshot_isolation_state由0变为1,如下图所示:

实验3:使用行版本控制的已提交读隔离(READ_COMMITTED_SNAPSHOT)

在此示例中,使用行版本控制的已提交读事务与其他事务并发运行。已提交读事务的行为与快照事务的行为有所不同。与快照事务相同的是,即使其他事务修改了数据,已提交读事务也将读取版本化的行。与快照事务不同的是,已提交读将执行下列操作:

  • 在其他事务提交数据更改后,读取修改的数据。
  • 能够更新由其他事务修改的数据,而快照事务不能。

query1:事务1

View Code

query2:事务2 

View Code

总结:

  1. 在事务2修改数据之后,提交之前,事务1中读到的是快照数据,也就是事务2没有修改之前的值。
  2. 在事务2提交修改之后,事务1读到了修改之后的数据。并且事务1可以修改由其他数据修改了的数据。

结论

  1. 使用 sys.databases 目录视图可以确定两个行版本控制数据库选项的状态。
  2. 对用户表和存储在 master 和 msdb 中的某些系统表的任何更新都会生成行版本。
  3. 在 master 和 msdb 数据库中,ALLOW_SNAPSHOT_ISOLATION 选项自动设置为 ON,并且不能禁用。
  4. 在 master 数据库、tempdb 数据库或 msdb 数据库中,用户不能将 READ_COMMITTED_SNAPSHOT 选项设置为 ON。
  5. 从上面的测试可以看到,原先会发生阻塞的两个会话在使用行版本控制的隔离级别后,都不会遇到阻塞了。但是两种行版本控制的结果又有不同。可以用表1来总结。

表1  使用行版本控制隔离级别后的不同

会话1

会话2

结果

A. 普通已提交事务

B. 使用快照隔离

C. 使用行版本控制的已提交读

BEGIN TRAN

查询1

 

48

 

BEGIN TRAN

修改1

成功

 

查询1

40

查询2

 

被阻塞

48

 

COMMIT TRAN

查询2返回40

 

查询3

 

40

48

40

修改2

ROLLBACK TRAN

 

成功

失败

成功

 补充:如果要查看锁状态,可以使用如下两种方法:

View Code

 

 

 本文转自xwdreamer博客园博客,原文链接:http://www.cnblogs.com/xwdreamer/archive/2012/07/30/2615357.html,如需转载请自行联系原作者

 

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
SQL PHP 数据库
sqlserver数据库查询某个字段 为null的所有行数据
sqlserver数据库查询某个字段 为null的所有行数据
315 0
|
索引
SqlServer性能优化之获取表的数据行数,数据大小,索引大小等
SqlServer性能优化之获取表的数据行数,数据大小,索引大小等
11118 0
|
测试技术 C#
解剖SQLSERVER 第十二篇 OrcaMDF 行压缩支持(译)
原文:解剖SQLSERVER 第十二篇 OrcaMDF 行压缩支持(译) 解剖SQLSERVER 第十二篇   OrcaMDF 行压缩支持(译) http://improve.dk/orcamdf-row-compression-support/ 在这两个月的断断续续的开发工作中,我终于将OrcaMDF 压缩功能分支合并到主分支这意味着OrcaMDF 现在正式支持数据行压缩功能 支持的数据类型实现行压缩需要我修改几乎所有已实现的数据类型以将他们作为压缩存储。
1020 0
|
存储
解剖SQLSERVER 第十三篇 Integers在行压缩和页压缩里的存储格式揭秘(译)
原文:解剖SQLSERVER 第十三篇 Integers在行压缩和页压缩里的存储格式揭秘(译) 解剖SQLSERVER 第十三篇    Integers在行压缩和页压缩里的存储格式揭秘(译) http://improve.dk/the-anatomy-of-row-amp-page-compressed-integers/ 当解决OrcaMDF对行压缩的支持的时候,视图解析整数的时候遇到了一些挑战。
1099 0
|
13天前
|
SQL 人工智能 算法
【SQL server】玩转SQL server数据库:第二章 关系数据库
【SQL server】玩转SQL server数据库:第二章 关系数据库
52 10
|
1月前
|
SQL 数据库 数据安全/隐私保护
Sql Server数据库Sa密码如何修改
Sql Server数据库Sa密码如何修改
|
2月前
|
SQL 算法 数据库
【数据库SQL server】关系数据库标准语言SQL之数据查询
【数据库SQL server】关系数据库标准语言SQL之数据查询
96 0
|
2月前
|
SQL 算法 数据库
【数据库SQL server】关系数据库标准语言SQL之视图
【数据库SQL server】关系数据库标准语言SQL之视图
77 0
|
1月前
|
SQL 数据库
sql server中创建数据库和表的语法
sql server中创建数据库和表的语法
18 1
|
1月前
|
SQL 安全 数据库
SQLServer 实现数据库表复制到另一个数据库_kaic
SQLServer 实现数据库表复制到另一个数据库_kaic