云计算百科
云计算领域专业知识百科平台

[小技巧55]深入解析数据库日志机制:逻辑日志、物理日志与物理逻辑日志在 MySQL InnoDB 中的实现

一、引言:日志是数据库可靠性的基石

在现代数据库系统中,日志(Logging) 是实现 原子性(Atomicity) 和 持久性(Durability) 的核心机制。根据记录内容的抽象层次,数据库日志通常分为三类:

  • 逻辑日志(Logical Logging)
  • 物理日志(Physical Logging)
  • 物理逻辑日志(Physiological Logging)

这三种日志在粒度、语义、恢复方式和适用场景上存在显著差异。

二、三种日志格式详解

1. 逻辑日志(Logical Logging)

  • 定义:记录事务的高层操作语义,如 SQL 语句或行级变更。
  • 特点:
    • 与存储结构无关;
    • 可跨版本、跨引擎重放;
    • 适用于复制、逻辑备份。
  • MySQL 实现:Binary Log(binlog)
    • STATEMENT 格式:记录原始 SQL;
    • ROW 格式:记录主键 + 列值变更(仍属逻辑层,因不涉及页/偏移)。
    • mixed格式:混合模式

示例(ROW 格式):

Table_map: test.T
Write_rows: (c1=1, c2='abc')

2. 物理日志(Physical Logging)

  • 定义:记录底层存储的字节级变化,如“将页 X 偏移 Y 处的 Z 字节从 A 改为 B”。
  • 特点:
    • 高度依赖页格式;
    • 恢复时直接 memcpy 覆盖内存;
    • 无法支持页结构演进。
  • MySQL 实现:InnoDB 未使用纯物理日志。
  • 典型系统:LevelDB WAL、早期 Berkeley DB。

InnoDB 不采用此模式,因其无法兼容压缩页、加密页等高级特性。

3. 物理逻辑日志(Physiological Logging)

  • 定义:以 物理页为作用域,记录 页内的逻辑操作,在页 X 上插入记录 Y。
  • 特点:
    • 日志 = <page_id, operation, args>;
    • 恢复时调用存储引擎函数重做操作(非字节覆写);
    • 兼顾效率与灵活性。
  • MySQL 实现:InnoDB Redo Log

✅ 示例:

<MLOG_REC_INSERT, space=1, page_no=100, record=(1,'abc'), index_id=PRIMARY>
<MLOG_REC_INSERT, space=1, page_no=200, record=(1,ptr), index_id=key_c1>

三、以一条 INSERT 为例:三种日志的生成对比

假设执行:

CREATE TABLE T (c1 INT, c2 VARCHAR(10), KEY(c1)) ENGINE=InnoDB;
INSERT INTO T VALUES (1, 'abc');

插入一行 (1, 'abc'),涉及:

  • 聚簇索引(主键索引,默认基于 rowid 或隐式主键)
  • 二级索引 key_c1

通常至少修改 两个 B+ 树页(聚簇索引页 + 二级索引页)。

1. 逻辑日志(Logical Log)记录情况

  • 记录内容:事务的高层语义
  • 示例:<INSERT, table=T, values=(1, 'abc')>
  • MySQL 对应:binlog(ROW 格式)Table_map: T
    Write_rows: (1, 'abc')

  • 数量:1 条(整个 INSERT 操作)

2. 物理逻辑日志(Physiological Log)记录情况

  • 记录内容:页 ID + 页内逻辑操作
  • 示例:<MLOG_REC_INSERT, space_id=1, page_no=100, record=(1, 'abc', DB_ROW_ID=…), index_id=PRIMARY>
    <MLOG_REC_INSERT, space_id=1, page_no=200, record=(1, ptr_to_clustered), index_id=key_c1>

  • 特点:
    • 每条日志绑定一个 page_no;
    • 记录的是 “在页 X 上插入记录 Y”,而非字节;
    • 恢复时需调用 InnoDB 的 page_cur_insert_rec_low() 等函数重做。
  • MySQL 对应:InnoDB Redo Log
  • 数量:≥2 条(每个被修改的页至少一条)

特殊情况
只有聚簇索引(无二级索引):插入数据

InnoDB 内部操作:

  • 在 聚簇索引(基于 DB_ROW_ID)中插入一条记录;
  • 该记录包含:DB_ROW_ID(自动生成)、a=1、b='abc';
  • 此操作只涉及 一个 B+ 树(即聚簇索引树);
  • 如果插入导致页分裂(page split),还会额外产生:
    • 创建新页的日志(MLOG_PAGE_CREATE);
    • 更新父页指针的日志(如果是非叶子页)。
  • 场景redo log 条数
    插入到已有页(无分裂) 1 条(MLOG_REC_INSERT)
    插入导致页分裂 ≥2 条(MLOG_PAGE_CREATE + MLOG_REC_INSERT + 可能的父页更新)

    即使只有 1 条用户记录插入,也可能因 B+ 树结构维护产生多条 redo log。

    3. 物理日志(Physical Log)记录情况

    • 记录内容:字节级变更(offset + old/new value)
    • 示例(针对一个页的多次修改):<space=1, page=100, offset=24, new_value=0x0005> // 页头:记录数从 4→5
      <space=1, page=100, offset=16380, new_value=0x0064> // Slot 数组更新
      <space=1, page=100, offset=200, new_value=…> // 新记录内容
      <space=1, page=100, offset=prev_rec+2, new_value=…> // 前一条记录的 next 指针

    • 数量:每个页可能产生 N 条(N ≥ 3~5 很常见)
    • MySQL 是否使用?:否。InnoDB 不使用纯物理日志。

    对比表

    日志类型记录粒度生成内容数量是否由 InnoDB 生成
    逻辑日志 表/行级操作 <INSERT, T, (1,'abc')> 1 条 通过 binlog
    物理逻辑日志 页 + 页内逻辑操作 两条页级插入操作,分别对应聚簇索引和二级索引页的插入操作 ≥2 条 InnoDB redo log
    物理日志 字节偏移 多条字节修改(页头、slot、指针等) ≥2×N 条 InnoDB 不生成

    关键洞察:
    InnoDB 跳过纯物理日志,直接从逻辑操作生成 physiological redo log,避免了字节日志的冗余与脆弱性。

    四、InnoDB 为何选择 Physiological Logging?

    优势说明
    支持页格式演进 即使 InnoDB 修改页结构(如引入新字段),只要操作语义不变,旧日志仍可重放
    兼容压缩/加密页 日志记录“插入记录”,而非“写入偏移”,可在解压后页上安全重做
    日志体积小 插入一条记录仅需 ~50 字节日志,而非 16KB 页
    恢复安全性高 通过调用 B+ 树函数重做,确保页结构一致性(如链表、slot 更新正确)

    五、日志协同:Redo Log + Binlog + Doublewrite Buffer

    InnoDB 的可靠性依赖三大组件协同:
    在这里插入图片描述

    • Redo Log(Physiological):保证页级操作可重做;
    • Doublewrite Buffer:保证页本身完整(防 partial page write);
    • Binlog(Logical):保证事务可复制、可 PITR(时间点恢复)。

    注意:只有当 innodb_flush_log_at_trx_commit=1 且 sync_binlog=1 时,才能实现真正的 crash-safe replication。

    六、三种日志核心特性

    特性逻辑日志物理日志物理逻辑日志
    记录粒度 表/行级 字节级 页 + 页内操作
    是否依赖存储结构 部分(需页 ID)
    恢复方式 重执行 SQL memcpy 覆写 调用存储引擎函数
    日志体积 极大 中等
    MySQL 组件 binlog InnoDB redo log
    适用场景 复制、备份 简单 KV 存储 崩溃恢复

    MySQL 通过 分层日志设计 实现了高可靠与高性能的统一:

    • 逻辑日志(binlog) 面向应用与复制;
    • 物理逻辑日志(redo log) 面向存储引擎崩溃恢复;
    • Doublewrite Buffer 作为最后一道防线,保障页完整性。

    七、面试题

  • Q:MySQL 中哪些日志属于逻辑日志?哪些属于物理逻辑日志?
    A:binlog 是逻辑日志;InnoDB redo log 是物理逻辑日志(physiological logging)。

  • Q:为什么 InnoDB 不使用纯物理日志?
    A:纯物理日志无法支持页压缩、加密、格式演进,且恢复时缺乏语义校验,易导致页损坏。

  • Q:一条 INSERT 会产生几条 redo log?为什么?
    A:至少两条——聚簇索引页和每个二级索引页各一条,因为每个 B+ 树页的修改需独立记录。

  • Q:Physiological logging 如何保证恢复正确性?
    A:恢复时调用 InnoDB 的页管理函数(如 insert/delete)重做操作,确保页内结构(链表、slot 等)一致。

  • Q:binlog 和 redo log 能否互相替代?
    A:不能。binlog 用于实例级复制,redo log 用于引擎级崩溃恢复,二者目标不同,必须共存。

  • 赞(0)
    未经允许不得转载:网硕互联帮助中心 » [小技巧55]深入解析数据库日志机制:逻辑日志、物理日志与物理逻辑日志在 MySQL InnoDB 中的实现
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!