如果再有人问你数据库的原理,把这篇文章给他(17)

这将提高性能,因为:

  • 读事务不会阻塞写事务
  • 写事务不会阻塞读
  • 没有『臃肿缓慢』的锁管理器带来的额外开销
除了两个事务写相同数据的时候,数据版本控制各个方面都比锁表现得更好 。只不过,你很快就会发现磁盘空间消耗巨大 。
数据版本控制和锁机制是两种不同的见解:乐观锁和悲观锁 。两者各有利弊,完全取决于使用场景(读多还是写多) 。关于数据版本控制,我推荐这篇非常优秀的文章,讲的是PostgreSQL如何实现多版本并发控制的 。
一些数据库,比如DB2(直到版本 9.7)和 SQL Server(不含快照隔离)仅使用锁机制 。其他的像PostgreSQL, MySQL 和 Oracle 使用锁和鼠标版本控制混合机制 。我不知道是否有仅用版本控制的数据库(如果你知道请告诉我) 。
如果你读过不同级别的隔离那部分内容,你会知道,提高隔离级别就会增加锁的数量和事务等待加锁的时间 。这就是为什么多数数据库默认不会使用最高级别的隔离(即串行化) 。
当然,你总是可以自己去主流数据库(像MySQL, PostgreSQL 或 Oracle)的文档里查一下 。
日志管理器
我们已经知道,为了提升性能,数据库把数据保存在内存缓冲区内 。但如果当事务提交时服务器崩溃,崩溃时还在内存里的数据会丢失,这破坏了事务的持久性 。
你可以把所有数据都写在磁盘上,但是如果服务器崩溃,最终数据可能只有部分写入磁盘,这破坏了事务的原子性 。
事务作出的任何修改必须是或者撤销,或者完成 。
有 2 个办法解决这个问题:
  • 影子副本/页(Shadow copies/pages):每个事务创建自己的数据库副本(或部分数据库的副本),并基于这个副本来工作 。一旦出错,这个副本就被移除;一旦成功,数据库立即使用文件系统的一个把戏,把副本替换到数据中,然后删掉『旧』数据 。
  • 事务日志(Transaction log):事务日志是一个存储空间,在每次写盘之前,数据库在事务日志中写入一些信息,这样当事务崩溃或回滚,数据库知道如何移除或完成尚未完成的事务 。
WAL(预写式日志)
影子副本/页在运行较多事务的大型数据库时制造了大量磁盘开销,所以现代数据库使用事务日志 。事务日志必须保存在稳定的存储上,我不会深挖存储技术,但至少RAID磁盘是必须的,以防磁盘故障 。
多数数据库(至少是Oracle, SQL Server, DB2, PostgreSQL, MySQL 和 SQLite) 使用预写日志协议(Write-Ahead Logging protocol,WAL)来处理事务日志 。WAL协议有 3 个规则:
  • 1) 每个对数据库的修改都产生一条日志记录,在数据写入磁盘之前日志记录必须写入事务日志 。
  • 2) 日志记录必须按顺序写入;记录 A 发生在记录 B 之前,则 A 必须写在 B 之前 。
  • 3) 当一个事务提交时,在事务成功之前,提交顺序必须写入到事务日志 。

如果再有人问你数据库的原理,把这篇文章给他

文章插图
 
这个工作由日志管理器完成 。简单的理解就是,日志管理器处于缓存管理器(cache manager)和数据访问管理器(data access manager,负责把数据写入磁盘)之间,每个 update / delete / create / commit / rollback 操作在写入磁盘之前先写入事务日志 。简单,对吧?
回答错误! 我们研究了这么多内容,现在你应该知道与数据库相关的每一件事都带着『数据库效应』的诅咒 。好吧,我们说正经的,问题在于,如何找到写日志的同时保持良好的性能的方法 。如果事务日志写得太慢,整体都会慢下来 。
ARIES
1992年,IBM 研究人员『发明』了WAL的增强版,叫 ARIES 。ARIES 或多或少地在现代数据库中使用,逻辑未必相同,但AIRES背后的概念无处不在 。我给发明加了引号是因为,按照MIT这门课的说法,IBM 的研究人员『仅仅是写了事务恢复的最佳实践方法』 。AIRES 论文发表的时候我才 5 岁,我不关心那些酸溜溜的科研人员老掉牙的闲言碎语 。事实上,我提及这个典故,是在开始探讨最后一个技术点前让你轻松一下 。我阅读过这篇 ARIES 论文 的大量篇幅,发现它很有趣 。在这一部分我只是简要的谈一下 ARIES,不过我强烈建议,如果你想了解真正的知识,就去读那篇论文 。
ARIES 代表『数据库恢复原型算法』(Algorithms for Recovery and Isolation Exploiting Semantics) 。
这个技术要达到一个双重目标: