暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

​浅析SQL Server乐观并发

云趣科技 2016-09-01
978

SQL Server的悲观并发

SQL Server天生是按悲观模式设计, 也就是说SQL 默认没有实现MVCC(Multiversion concurrency control
—多版本并发控制机制). SQL Server默认的事务隔离级别Read Committed
模式下, 读写是会相互阻塞的. 对于有Oracle背景, 默认支持多并发一致读, 读写相互不阻塞的开发或者DBA来说, 很不习惯.

一个例子, 创建表t, 并且插入一行数据, 使用SET IMPLICIT_TRANSACTIONS on
关闭自动提交,

create table tttt (id int primary key);SET IMPLICIT_TRANSACTIONS on;insert into t values(1);
复制

此时在另外一个会话查询表T, 会被阻塞

select * from ttt;
复制

从云趣鹰眼的可以看到阻塞情况, 查询语句等待类型是共享所LCK_M_S
, 被插入语句阻塞. 这时SQL Server高并发时非常容易遇到一种锁等待, 严重影响应用系统的性能和扩展性.


暴力解决方案

可以通过with (nolock)
或者设置事务隔离级别为READ UNCOMMITTED
. 来避免查询被DML语句阻塞. 但是这种隔离级别允许查询语句读到脏数据, 比如可能读到已经插入但是没有提交的数据或者丢失更新的数据, 不适用于严肃的应用场景.

SQL Server的乐观并发

为了提高并发性, SQL Server从2005开始, 支持乐观并发, 可以实现类似Oracle的多版本读保证一致性. 乐观并发采用行版本存储技术, 当需要插入, 或者修改某一行时, 新值会被标识上XSN, 前一个版本的数据会存放到TempDB, 类似于Oracle的undo表空间. SQL Server新的版本会通过指针指向旧的版本数据, 类似Oracle的数据库中ITL结构.

乐观并发中包含两种快照隔离级别:

  • READ COMMMITED SNAPSHOT ISOLATION(RCSI)
    : 返回当前语句开始时的结果, 可以通过以下语句开启RCSI, 这个语句当前所有事务终止之后才能执行成功:

    ALTER DATABASE yunqu SET READ_COMMITTED_SNAPSHOT ON;
    复制
  • SNAPSHOT ISOLATION(SI)
    : 返回当前事务开始时的结果, 可以通过以下语句开启SI, 这个语句当前所有事务终止之后才能执行成功:

ALTER DATABASE yunqu SET ALLOW_SNAPSHOT_ISOLATION ON;
复制

修改数据库启用乐观并发之后, 还需要在回话级别设置事务隔离级别为snapsnot:

set transaction isolation level snapshot; select * from tt;
复制

这时, 查询就不会被插入语句阻塞了.

使用乐观并发的主意事项

  • 因为DML操作需要存储就版本到TempDB, 需要对TempDB做一些管理. 比如TempDB默认大小只有8MB, 按10%的比例增长. 这在数据增删改频繁高负载的应用中可能是不适合, 建议把TempDB大小设置为200~500MB.

  • SQL Server在新版本中默认事务隔离级别依然为悲观模式下的READ COMMITED. 并不存在一个全局的设置更改默认的事务隔离级别为快照隔离, 也无法通过Logon trigger
    等方法来使某一个用户默认使用快照隔离. 应用只能在建立连接之后运行set transaction isolation level snapshot
    来主动启用乐观并发模式, 这是比较令人遗憾的, 这意味着所有的SQL Server应用除非在代码中手动配置, 否则无法使用乐观并发模式.

文章转载自云趣科技,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论