当前位置:首页 > 问答 > 正文

SQL Server里头无锁那点事,怎么保证数据安全又能快起来,不用加锁也行吗?

知乎专栏《SQL Server技术内幕》、微软官方文档《SQL Server事务处理与并发控制》、博客园博文《高并发下的数据库无锁方案探索》)

在SQL Server里,一提到多个用户同时操作数据,大家的第一反应可能就是“加锁”,锁就像是给数据房间派了个保安,一次只让一个人进去改东西,这样肯定不会乱,但门口排队的人多了,系统就“快不起来”了,有没有可能不用保安,或者换个更聪明的办法,既能保证数据安全,又能让大家不用排队,快起来呢?答案是肯定的,SQL Server确实提供了一些“无锁”或“少锁”的招数。

SQL Server里头无锁那点事,怎么保证数据安全又能快起来,不用加锁也行吗?

首先得明白,为什么非要“锁”? 根本原因是为了对付并发操作带来的三个“妖怪”:脏读、不可重复读和幻读,锁是解决这些问题最直接的工具,但它代价高,容易导致阻塞和死锁,拖慢整体性能。

那不加锁真的行吗? 在某些特定场景下,真的可以,SQL Server提供了两种主要的“无锁”魔法:快照隔离和行版本控制,它们核心思路不是不让别人读,而是“你改你的,我读我的副本”。

SQL Server里头无锁那点事,怎么保证数据安全又能快起来,不用加锁也行吗?

第一招:基于行版本控制的快照隔离 这个功能就像是给数据库开了个“时光机”。(来源:微软官方文档《SQL Server事务处理与并发控制》) 当你启动一个事务要读数据时,SQL Server不会傻等着别人释放锁,而是立刻去创建一个数据在某个时间点的“快照”(其实就是一份旧版本的数据副本),你的所有读操作都是在这个快照上进行的,所以完全不会受到其他正在修改数据的事务干扰,这样一来,读操作根本不需要申请共享锁,自然就不会和修改数据的排他锁发生冲突,实现了读不阻塞写、写也不阻塞读。

这听起来很美好,但代价是什么呢?代价就是需要额外的空间来存储这些旧版本的数据副本(存在tempdb里),如果系统有大量、长时间的修改操作,tempdb的压力会很大,可能成为新的瓶颈,这招适合读非常频繁,而写相对较少的系统。

SQL Server里头无锁那点事,怎么保证数据安全又能快起来,不用加锁也行吗?

第二招:已提交读快照 这是快照隔离的一个“青春版”,更常用也更轻量。(来源:博客园博文《高并发下的数据库无锁方案探索》) 你不需要显式地设置事务隔离级别为快照隔离,只需要在数据库级别开启一个选项READ_COMMITTED_SNAPSHOT,开启后,默认的已提交读隔离级别就变样了,它的行为变成了:读数据时,永远去读那个最近一次已提交的版本,这样也避免了读操作加共享锁,从而避免了和写操作的冲突,这个改动对应用程序通常是透明的,很多性能问题就这样悄无声息地解决了。

第三招:内存优化表 这是SQL Server引入的“大杀器”,真正意义上可以做到无锁。(来源:知乎专栏《SQL Server技术内幕》) 传统表的数据放在磁盘上,叫“基于磁盘的表”,它们的并发控制严重依赖锁和闩锁,而内存优化表是把整个表的数据都放在内存里,速度极快,它彻底抛弃了传统的锁机制,改用一种乐观的并发控制方式,它假设不同的事务很少会去修改同一行数据,事务执行时,不会加任何锁,直接干,但在提交时,系统会校验一下,看看在你事务运行的过程中,有没有别人修改过你要的数据,如果没有,恭喜你,提交成功,如果有冲突,你的事务就会被终止回滚,这种方式特别适合那种争用很少,但需要极高吞吐量和低延迟的场景。

除了这些,还有一些“曲线救国”的思路:

  1. 精细化的索引设计:(来源:多位DBA的实践经验总结)好的索引能让查询更快地定位到数据,缩短事务持有锁的时间,相当于减少了“锁”带来的负面影响,这虽然不是直接无锁,但通过“快进快出”策略,大大降低了锁的危害。
  2. 使用序列对象:像生成订单号、流水号这种需求,以前可能用标识列或者自己维护一个表,这都可能产生锁竞争,SQL Server的序列对象是一种高性能、无锁的序列生成机制,能很好地解决这个问题。

回到“不用加锁也行吗?”这个问题。 答案是:看情况

  • 如果你的场景是读多写少,担心读操作被写操作阻塞,那么开启已提交读快照是一个非常棒且低成本的起点。
  • 如果你需要更严格的一致性(比如可重复读),且能承受tempdb的开销,可以考虑快照隔离
  • 如果你的系统有极其苛刻的性能要求,数据争用又不高,那么内存优化表是通往极致性能的路径。
  • 任何时候,优化查询和索引都是减少锁冲突的基石。

SQL Server提供了超越传统加锁的多种工具,完全“无锁”是一种理想状态,但在很多实际场景中,通过巧妙地使用这些技术,我们可以最大限度地“减少锁”的使用,在保证数据安全的前提下,让数据库真正地“快起来”,关键在于根据你的业务特点,选择最合适的武器。