wal 日志说白了,就是给数据库加的一层“定时呼吸”。

你想象一下,数据库里的数据每天都在变,写快了,写晚了,就连断网了,有啥好办法让它一辈子记住“昨天 10 点 50 分这一条数据,应当放在哪一列,看哪位写的,哪位写的”。 wal 就负责记这些“昨天”的历史动作。它不像一般/平平的日志那样只记录啥操作,而是专门记录“啥工夫点、哪位操作、做了啥、到了哪一行”。 这玩意儿对数据库本身实际上没啥额外负担,它就是个内存里的影子。

只要系统没崩溃, wal 就老老实实跑在后台,不讲话,不动手。它干的最大任务就是帮数据库做“工夫轴”的分身。 拿 MySQL 8.0 这种新一代数据库来说,wal 的核心功能就是给每条 SQL 命令打上工夫戳标签。你执行一条 `DELETE` 语句,wal 会立马生成一条记录,里面写着“10 月 10 日 14:02:35 用户 A 执行了删除”。

这时候你再去查旧表,用 `SELECT FROM table WHERE time = 14:02:35` 查,找到的不仅是你刚刚那条删数据,还有你删数据前、删数据后、就连删数据之前半小时做的所有事。

这就好比你在灶台间切菜,切的时候桌上摆满了菜,切完立马停,但桌上能闻到那股香,也能看到那碗刚切的菜。wal 就是那个记录“桌上摆着啥菜”的备忘录。 别看 wal 主要是记动作,但它也能记状态。大量时候,一条 SQL 执行是个顿号,比如 `UPDATE` 要么 `INSERT`,它要么成功要么黄了,中间挺难分秒不差地记录每一步细节。 wal 就把这个“成败”也塞进去了,要么说,它更关心这个动作形成在啥工夫点,是否成功。

要是一条记录黄了了,wal 会默认把这个动作标记为黄了,这样查询的时候,系统就知道那条数据已经被改了,要么根本没动过。 wal 还有一个挺实用的功能,就是“历史快照”。假设你刚查完数据,立马又改了一行,这时候要是直接查,那条旧数据可能就不见了。wal 就帮你在刚刚那条修改之前,拍了一张“老照片”。你查的时候,直接问 wal,让它把“修改前”这个工夫点的数据给你。在数据库里查,“修改前”一般是指 `before_time` 这一行,wal 里存的就是 `before_time` 这一行对应的历史快照。 这里头有个细节,wal 记录的工夫戳和实际执行工夫不一样。

比如你 10 点 50 分写完代码,但数据库报错 10 点 51 分,wal 可能只记录 10 点 50 分。出于 wal 是写进磁盘的,写磁盘的速度慢,故此它记录的工夫一般是执行工夫减去那一两个毫秒。

这个工夫差对于精确到秒级的分析来说,一般能够忽略不计,但要是是做秒级就连分钟级定位,这个几百毫秒的误差就显得有点“富贵闲人”了。Wal 日志的查询速度,相当便你拿一把小锤子敲桌子,而一般/平平查询用的是电动钻。敲桌子别看慢,但声音大,好办看到啥;电动钻快,但没声音,也看不见。 wal 还有个特征,就是它和数据库的内存是隔开的。数据库本身有内存,用来存当前的热点数据,比如你正在看的聊天界面,那些最新的数据都在内存里。wal 是另一套系统,它不占用数据库的内存空间,它只占用你自己的硬盘空间。

这就像你家里有个大衣柜,用来放你换季的衣服(数据库内存),还有一个专门的小柜子,用来放你半年前的旧衣服(wal 日志)。新衣服和新旧衣服互不干扰。 举个例子,你看目前的消息推送服务,大量时候不是直接查数据库查“这条消息是几秒前发的”,而是查 wal。

为啥?出于数据库里那颗关于“这张消息”的叶子节点可能早就被清理了,要么已经被合并了,它根本没存着整个的工夫戳。

可是 wal 里,那颗工夫戳记录活着,还在原来的工夫线上。wal 查起来,就像是直接翻到了那张工夫戳那一页,直接取出来。 wal 还有一个挺有意思的特性,叫“覆盖”。数据库里的数据是活的,随时可能被自己或别人更新。但 wal 记录的是“那会儿式”。

哪怕你后面加了一行 `INSERT` 把wal那条记录覆盖掉了,只要 wal 没在更早的工夫点把它写完,要么在更晚的工夫点写完,wal 里的那条记录就逃不掉。它记录的是“此时此刻的快照”,哪怕后面形成了啥,wal 里的这个快照依然是“此时此刻的样子”。 wal 的操作实际上挺好办的,主要是写盘。它把工夫戳、哪位、做了啥、到哪一行,这些信息按工夫顺序塞进文件。

要是系统重启了,wal 再启动,它就从那个文件里重新读一遍,彻底不需求看数据库里到底存了啥,也不需求问数据库“这里面有没这条记录”。它直接读文件,文件里写的是啥,数据库里就存啥。

这是一种“以写代查”的策略,效率极高。 最终说回 wal 和一般/平平日志的区别。

一般/平平日志是记录你“做了啥动作”,比如“用户 A 点击了按钮”。wal 是记录你“点击了按钮,工夫戳是 10 点,用户 ID 是 123456789"。

一般/平平日志是流水账,wal 是带工夫的流水账,并且带身份标签的。 wal 就在这个“工夫 + 身份 + 动作”的三维结构上,把数据库的历史动作给冻结下来了。它让数据库变成了一个庞大的工夫机器,你能够随时按工夫倒带,也能够按工夫推进,随时按人回溯。

这不只是是 MySQL 能做到的,任何赞成 WAL 记录的数据库,从 Oracle 到 PostgreSQL,再到最新的 Redis,都在做同样的事件。wal 本质上就是把数据库的“线性工夫”变成了“可查询的历史”,让数据查询从“随机翻书”变成了“按工夫轴翻阅”,这才是它存有的真正价值。