InnoDB 内存结构总览:Change Buffer、AHI 与 Log Buffer

一、InnoDB 内存结构全景回顾

复制代码
InnoDB 内存结构
├── Buffer Pool           数据页/索引页缓存(上一篇)
├── Change Buffer          二级索引变更缓存(本篇)
├── Adaptive Hash Index    自动哈希索引(本篇)
├── Log Buffer             redo log 内存缓冲(本篇简述,磁盘部分见 redo 专篇)
└── Lock Sys / 其他        锁系统等(本篇不展开)

加粗要点 :Change Buffer 的缓存数据占用 Buffer Pool 空间,但它是独立逻辑子系统;AHI 是建立在 Buffer Pool 页上的派生结构


二、Change Buffer(变更缓冲区)

2.1 它解决什么问题

修改一条数据时,如果对应的二级索引页不在 Buffer Pool:

复制代码
朴素流程:
  ① 随机读磁盘:把二级索引页读进 Buffer Pool
  ② 修改该页,变成脏页
  ③ 以后再随机写回磁盘
→ 一次修改 = 至少两次随机 IO

Change Buffer 的思路:不立即读那个二级索引页,把变更操作先缓存起来;等以后这个页真的被访问(查询加载)时,再把缓存的变更批量合并进去。

2.2 原理

复制代码
一条 UPDATE/DELETE/INSERT 语句:
  ① 聚簇索引(主键):立即修改。因为聚簇索引叶子 = 数据行本身,必须立即写。
  ② 二级索引:
     ├─ 索引页已在 Buffer Pool → 直接修改,不经过 Change Buffer
     └─ 索引页不在 Buffer Pool → 把这条变更记录缓存到 Change Buffer
                                 (不立即从磁盘读页)

加粗要点 :只有"二级索引页不在内存"时才缓存;而且聚簇索引的修改永远是立即执行的。

2.3 为什么只缓存二级索引?

索引类型 叶子节点存什么 能否延后修改
聚簇索引(主键) 数据行本身 ❌ 必须立即改。插入一行数据,你必须知道它落在哪个数据页,这行数据就是页的内容
二级索引 索引列值 + 主键值(冗余结构) ✅ 可以延后。它是辅助查询的冗余副本,查询不走它就不影响结果

核心原因:聚簇索引 = 数据本身,不能延后;二级索引 = 冗余副本,可以慢慢维护。你插入一行新数据,必须立即把数据写到聚簇索引的叶子页(这是真实数据);但二级索引页暂时不在内存,先记一笔账,等以后真要查这个索引时再合并就行。

2.4 合并时机

复制代码
变更记录什么时候真正合并到二级索引页?
  ① 当查询把这个二级索引页从磁盘加载进 Buffer Pool 时(顺带合并)
  ② 系统正常关机时
  ③ Change Buffer 空间即将耗尽时(后台线程强制 merge)
  ④ 后台 master thread 定期合并

2.5 配置:innodb_change_buffering

复制代码
SET GLOBAL innodb_change_buffering = all;
-- 或在 my.cnf 中配置
取值 缓存什么
all(默认) inserts、delete marking、purges
none 什么都不缓存
inserts 只缓存插入
deletes 只缓存删除标记(delete marking)
changes inserts + delete marking
purges 只缓存后台物理删除操作

删除标记是什么?:

这里要区分两个阶段:

  • delete marking(删除标记) :UPDATE/DELETE 时,给记录头打一个 deleted 标记,记录逻辑上删了,但物理上还在页里(空间没释放);
  • purge(清除) :后台线程把这些"已标记删除"的记录真正从页里物理移除,释放空间。

所以:

  • deletes 缓存的是"打删除标记"这个动作;
  • purges 缓存的是"真正物理清除"这个动作;
  • 两者是删除流程的两个阶段。

三、Adaptive Hash Index(自适应哈希索引)

3.1 是什么

AHI 是 InnoDB 自动根据访问模式建立的哈希索引------不需要 DBA 手动创建。

复制代码
没有 AHI 时,一次等值查询:
  where id = 100
  → 从 B+Tree 根页开始,逐层往下找
  → 经过好几层目录页(可能不在内存,要读磁盘)

有 AHI 命中时:
  where id = 100
  → InnoDB 自动对频繁访问的索引键建了哈希
  → 直接通过哈希定位到数据页地址,跳过 B+Tree 层级遍历

3.2 关键特性

特性 说明
自动建立/拆除 InnoDB 监测访问模式,某页被频繁等值查询就建哈希;不热了自动拆
只支持等值查询 =、<=>、IN;不支持范围查询(BETWEEN、>、<)
占用 Buffer Pool 空间 哈希表本身在 Buffer Pool 内
分区减少锁竞争 innodb_adaptive_hash_index_parts 控制分区数

3.3 配置

复制代码
-- 是否开启 AHI(默认 ON)
SHOW VARIABLES LIKE 'innodb_adaptive_hash_index';

-- AHI 分区数(默认 8,并发越高锁竞争越少)
SHOW VARIABLES LIKE 'innodb_adaptive_hash_index_parts';

四、Log Buffer(日志缓冲区)

Log Buffer 是 redo log 的内存缓冲区:

复制代码
事务修改数据时:
  ① 先把 redo log 记录写到 Log Buffer(内存)
  ② 按策略(always/everysec)刷到磁盘 redo log 文件

加粗要点 :Log Buffer 的内存部分 就这一点;redo log 的磁盘格式、刷盘策略(innodb_flush_log_at_trx_commit)、崩溃恢复流程,在后续 redo log 专篇详细讲。


五、三种内存结构对比

结构 作用 占用哪块内存 关键点
Change Buffer 缓存二级索引变更,省随机 IO Buffer Pool 内 只缓存二级索引页不在内存的情况;聚簇索引立即改
AHI 自动哈希索引,加速等值查询定位 Buffer Pool 内 InnoDB 自动建/拆;只支持等值查询
Log Buffer redo log 内存缓冲,崩溃恢复用 独立内存区 磁盘部分见 redo 专篇

查看运行状态:

复制代码
SHOW ENGINE INNODB STATUS\G
-- 里面能看到 CHANGE BUFFER、ADAPTIVE HASH INDEX、LOG 等段落

六、总结

  1. Change Buffer:二级索引页不在内存时,先缓存变更,等页被加载时合并;聚簇索引必须立即改;
  2. 为什么只缓存二级索引:聚簇索引=数据本身,不能延后;二级索引是冗余副本;
  3. 合并时机:页被查询加载、关机、空间耗尽、后台定期 merge;
  4. delete marking vs purge:一个是打删除标记,一个是物理清除;
  5. AHI:InnoDB 自动建的哈希索引,只加速等值查询;
  6. Log Buffer:redo log 内存缓冲,磁盘机制见专篇。
相关推荐
招风的黑耳15 分钟前
SpringBoot+Vue+MySQL 民宿在线预定平台 完整可运行版(源码+文档)
vue.js·spring boot·mysql
花间相见21 分钟前
【计算基础|Redis02】【上手】五大数据类型命令逐条实操
数据库·redis·后端
敲上瘾1 小时前
Qt Widgets入门:项目模板解析与Hello World
开发语言·数据库·c++·qt·ui·qt6.3
bksczm2 小时前
Redis 持久化:RDB 快照与 AOF 日志
数据库·redis·mybatis
.痞老板.3 小时前
mysql初阶--数据库设计
数据库·mysql·oracle
Decay__4 小时前
SQL Server 数据库全栈运维实战系列 — 合集索引(24 篇)
运维·数据库·sql·mysql·架构
Thanks_ks4 小时前
SQL 的 GROUP BY 与聚合函数:从会写 SELECT 到会做统计
数据库·sql·mysql·group by·数据统计·聚合函数·having
Decay__12 小时前
12_MySQL InnoDB 内存与锁调优 —— Buffer Pool、redo log、隔离级别与锁等待
运维·数据库·sql·mysql·架构
笃行35013 小时前
AI数据库的库内四层结构,KingbaseES 产品拆解
数据库