开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,SQL Server,Redis ,Oracle ,Oceanbase 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请加微信号 liuaustin3 (共1250人左右 1 + 2 + 3 +4)新人会进入3群 (3群准备关闭自由申请)
每天感悟
go
好像现代人不焦虑就不正常,为了孩子,为了身体,为了工作,为了钱财,为了每天安全的食品,焦虑是每天的必修课,焦虑中饱含希望一切都按照自己的想法运转,自己仿佛是宇宙的中心,为什么就不能按我心意,如意如意,麻烦醒醒,你脚离地了。
SQL SERVER 好久没有写了,偶然有人问SQL SERVER 的UNDO REDO 怎么实现的,因为这些人不曾听说SQL SERVER 有 autovacuum ,vacuum ,也不曾听说 SQL SERVER 有UNDO 表空间,REDO 日志,到底SQL Server是怎么实现,传统数据库中需要的,前滚翻和后滚翻,我们今天看看,到底SQL SERVER 和那个数据库有近亲关系。
首选需要确认的,SQL SERVER 的确没有和ORACLE 以及MYSQL 同流合污,走了UNDO 表空间的这条路,也没有和PostgreSQL 一样将UNDO 深藏在每个自己的表内,他走的是完全依靠日志的的这条路。
在SQL SERVER 中饱含了数据文件MDF NDF,以及SQL SERVER 最硬核的日志,LDF 文件,而 LDF 文件,承载了SQL SERVER 的 REDO ,UNDO 的两个数据库核心功能的实现。
首先我们需要确认一个前提,无论那种数据库的WAL ,write ahead log 都是顺序的,有时间性和顺序性,在确认这点后,我们就可以很少的解释SQL SERVER 到底怎么单纯通过日志就可以完成,那些数据库通过日志无法完成的 UNDO 。
这里需要说明,SQL SERVER LDF 文件本身是被切成多个VLF 块的,而这些块有正在被使用的,也有还未激活的,整体的日志VLF 是循环使用每个VLF 中会写事务的日志,每个日志占用512bytes 到 60KB 不同大小的,来记录每个事务的工作。
这里会对不同的日志块,进行标记那些那些事务是活跃的,而那些是已经提交的。当一个VLF 写满后,就开启下一个VLF 来继续写日志,所以SQL SERVER 的日志是一个非常复杂的结构。
那么SQL SERVER 回滚,需要做的就是将ACTIVE 的事务日志block,进行反向翻译,然后执行就可以得到事务的回滚。下图中事务1 事务2都是并行运行的,当事务1发生问题,进行回滚,举例 事务1中为
insert into table 而产生回滚,则会产生反向语句 delete from table where XXXX. 所以通过一个逆向的操作,将正向的操作抵消掉。同时每个事务自身也有自己的序号,LDF 日志中通过 VLF 分块,然后每个事务占用VLF 中的 512 bytes 或 60KB 来记录事务,而其中会标记
1 事务的commit 还是uncommit
2 事务中的log block 顺序号
3 事务中 log block 中的事务详细执行的每一步的顺序
4 数据中操作修改的字段的值
所以SQL SERVER LDF 日志文件中,如果回滚将从原有的日志中,获取倒序的执行顺序,执行的值,等信息,产生逆向操作后,直接执行日志即可,数据库的操作可以随时进行rollback。这里与其他的数据库 ORACLE ,MySQL , PostgreSQL 的实现方式均不同,UNDO 的整体操作都在日志中完成。
这里小结一下,SQL SERVER 日志中饱含的信息
1 每个事务的是否活跃的信息标志
2 每个事务的序号
3 每个事务内部的序号
4 事务终止标志
5 回滚标志位 -- 反向事务日志
6 CheckPoint 标记位
通过这个SQL SERVER 事务的了解,也就明白如果有一个长事务不进行commit 则SQL SERVER 的LDF 文件会疯狂的进行扩展,无法进行回收。
同时回滚的事务较多的情况下,尤其大事务,则会导致回滚较慢以及LDF文件加大的问题。
通过学习也了解了三种UNDO实现的方式 SQL SERVER 是将冗余的回滚段放到了日志,POSTGRESQL是将回滚的数据放到了原表,ORACLE MYSQL则是单独设置了回滚段,4种数据库3种实现的UNDO的方式,也体现了每种数据库设计者的一些数据库设计的思路。
REDO 的实现在SQL SERVER 也更加的简单,还是通过LDF 日志文件来实现,在最后一次CHECKPOINT点前说明数据已经刷新到数据页面,则这些日志数据无需回滚,而在最后一次CHECKPOINT点标志位后的日志,则说明需要进行前滚。
单这里会出现一个问题,便是和POSTGRESQL 一样被DISS的 REDO 大量事务过慢的问题,这里POLARDB FOR POSTGRESQL 在代码中,将这部分变为了多线程的前滚模式,SQL SERVER 解决这个问题,开始并行REDO是在2012以后得版本,当然有一些BUG不够应该FIXED 了,SQL SERVER在 2019版本中又启用了ADR 新的功能。
ADR -- accelerated database recovery , 其中这个新的功能中饱含了新的组件
1 PVS persistent version store -- 存储事务中修改行前一个版本的行信息
2 logical revert 通过逻辑分析,在事务回滚时组织好如何读取前一个版本的信息
3 sLog 这个组件的信息是在内存中,比如一些还为写入PVS 的行信息
4 cleaner 清理PVS 中过期的行的信息
当启用ADR会在数据行中产生一个14个字节的指针,当行被修改后指针指向行之前的行版本,启用了ADR 后,之前SQL SERVER 大事务日志无法截断和快速收缩的问题得到了解决,但是会产生一个新得问题,和POSTGRESQL 一样,数据文件将变得大。
go
ALTER DATABASE [ADR] SET ACCELERATED_DATABASE_RECOVERY = OFF;
这里微软官方文档明确指出,如果你的应用是高频的UPDATE和 DELETE的操作数据库表,则不建议开启ADR功能。
所以SQL SERVER ADR的功能和 POSTGRESQL的某些设计是不是近亲,你心里应该有一个答案,当然好消息是,对于大事务的UNDO回滚,将比以往有更快的速度。
小结:在数据库的设计中,UNDO REDO 的实现的方式在不同的数据库有不同的设计的方式,各种数据库都在尽力的解决自身设计的缺陷并和其他数据库取长补短,回到题目,SQL SERVER 在有了ADR 后,和POSTGRESQL是不是有近亲关系?这可能还需要更深入的研究,但是在LINUX 系统中各种数据库互相"拳打脚踢"的局面不同,Windows server服务器的市场中,SQL Server 是隔岸观火,唯我独尊的状态。
最终,数据库的WAR 背后的投资者还是微软和甲骨文,敌人的敌人就是朋友被演绎的淋漓尽致。
参考文字