一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

PostgreSQL与MySQL数据库日志机制深度对比

时间:2026-07-16 08:23:09 编辑:袖梨 来源:一聚教程网

一、结论先行

PostgreSQL 没有 redo log、binlog、undo log。

PostgreSQL及MySQL数据库日志机制深度对比

只有 WAL 一套日志,承担了 MySQL 三套日志的全部职责。

二、MySQL 为什么需要三套日志

MySQL 的架构分为两层,导致日志也分裂成两层:

MySQL 架构┌─────────────────────────────────────┐│           Server 层                  ││   binlog(引擎无关,Server 自己记)   │├─────────────────────────────────────┤│         InnoDB 引擎层                ││   redo log(InnoDB 自己记)          ││   undo log(InnoDB 自己记)          │└─────────────────────────────────────┘
  • binlog:Server 层的逻辑日志,记录"执行了什么操作"
  • redo log:InnoDB 的物理日志,记录"数据页哪里改了"
  • undo log:InnoDB 的回滚日志,记录"改之前是什么"

这是历史包袱:MySQL 最初是插件式引擎架构,Server 层不知道引擎内部,只能各记各的。

三、三套日志各自的职责

3.1 redo log —— 崩溃恢复

写入时序:  事务提交    ↓  写 redo log(WAL,顺序写,快)    ↓  内存数据页标记为 dirty    ↓  checkpoint 时才把 dirty page 刷盘崩溃恢复:  重启 → 读 redo log → replay 未刷盘的变更 → 数据一致

对应 PostgreSQL:WAL 承担了完全相同的职责

3.2 binlog —— 主从复制 / 数据归档 / CDC

binlog 有三种格式:  STATEMENT:记录 SQL 语句(不精确,有歧义)  ROW:      记录行的前后变化(精确,CDC 必用)  MIXED:    混合模式主从复制流程:  主库 binlog → IO Thread → 从库 relay log → SQL Thread → 从库执行

对应 PostgreSQL:WAL logical decoding 承担了相同职责

3.3 undo log —— 事务回滚 + MVCC

UPDATE user SET name='Alice' WHERE id=1InnoDB 做法:  1. 把旧值 name='Bob' 写入 undo log  2. 数据页改为 name='Alice'(原地更新)  3. 事务回滚时:从 undo log 读旧值,恢复回去  MVCC 读旧版本:  另一个事务需要读 name='Bob'(旧快照)  → 从 undo log 回溯旧版本

对应 PostgreSQL:不需要 undo log,见下节

四、PostgreSQL 为什么不需要 undo log

这是 PG 和 MySQL MVCC 实现思路的根本差异

MySQL:原地更新(Update in Place)

数据页:  ┌──────────────────┐  │  id=1, name=Alice │  ← 只存最新版本  └──────────────────┘undo log:  ┌──────────────────┐  │  id=1, name=Bob   │  ← 旧版本存这里  └──────────────────┘读旧快照 → 去 undo log 里找

PostgreSQL:追加写(Append-Only Heap)

数据页:  ┌──────────────────────────────────────────────┐  │  Tuple1: id=1, name=Bob  [xmax=200, dead]    │  ← 旧版本,打标记  │  Tuple2: id=1, name=Alice [xmin=200, alive]  │  ← 新版本  └──────────────────────────────────────────────┘UPDATE = INSERT 一条新 tuple + 把旧 tuple 标记为 dead读旧快照 → 直接读同一数据页里的 dead tuple(根据 xmin/xmax 判断可见性)

代价:需要 VACUUM 清理

dead tuple 不会自动消失,需要 VACUUM 定期清理:  VACUUM table_name;  -- 或者 autovacuum 后台自动运行如果 VACUUM 跑不过来(写入太快)→ 表膨胀(Table Bloat)这是 PG 的独有问题,MySQL 没有

五、MySQL 的两阶段提交

由于 redo log 和 binlog 是两套独立的日志,MySQL 必须用两阶段提交保证一致性:

事务提交流程:  1. InnoDB 写 redo log(prepare 阶段)  2. Server 写 binlog  3. InnoDB 提交 redo log(commit 阶段)如果第 2 步崩溃:  重启后发现 redo log prepare 但 binlog 没有 → 回滚如果第 3 步崩溃:  重启后发现 binlog 有但 redo log 未 commit → 提交保证 redo log 和 binlog 始终一致

PostgreSQL 没有这个问题,因为只有一套 WAL,天然一致。

六、完整对比表

职责MySQLPostgreSQL
崩溃恢复redo log(InnoDB 层)WAL
主从复制binlog(Server 层)WAL Streaming Replication
CDC / 变更捕获binlog(ROW 格式)WAL Logical Decoding
事务回滚undo logWAL(未提交事务直接丢弃)
MVCC 旧版本undo log数据页内的 dead tuple
日志套数3 套1 套
架构复杂度高(两阶段提交协调)

七、各自的优缺点

PostgreSQL WAL 优点

✅ 架构简洁,一套日志全包✅ 无两阶段提交开销✅ WAL 顺序写性能极好✅ Logical Decoding 开箱即用,CDC 友好

PostgreSQL WAL 缺点 / 注意事项

⚠️ dead tuple 堆积需要 VACUUM,写入密集场景需要调优⚠️ wal_level=logical 会增加 WAL 体积(记录更多信息)⚠️ Replication Slot 如果消费方停止,WAL 文件不删除 → 磁盘风险

MySQL 日志优点

✅ undo log 独立,旧版本存储与数据文件分离,表不膨胀✅ binlog 格式成熟,生态丰富(Canal、Maxwell 等 CDC 工具)

MySQL 日志缺点

⚠️ 三套日志,维护复杂⚠️ 两阶段提交有额外开销⚠️ binlog 和 redo log 可能不一致(极端崩溃场景)⚠️ undo log 过大会影响读性能(长事务问题)

八、小结

MySQL:历史包袱导致三套日志  redo log  ← 崩溃恢复  binlog    ← 复制/CDC  undo log  ← 回滚/MVCCPostgreSQL:设计简洁,一套 WAL 全包  WAL              ← 崩溃恢复 + 复制 + CDC  heap dead tuple  ← MVCC 旧版本(替代 undo log)  代价不同:  MySQL  → 两阶段提交协调开销 + undo log 长事务问题  PG     → dead tuple 堆积需要 VACUUM 调优

总结 

热门栏目