什么是缓存命中
重要
在数据库系统中,为了提升性能,通常会使用缓冲池(Buffer Pool) —— 这是内存中的一块区域,用来缓存从磁盘读取的数据页(Data Pages)。当数据库需要读取某条记录时:
如果该记录所在的数据页已经在 Buffer Pool 中 → 称为 缓存命中(Cache Hit),直接从内存读取,速度快。
如果不在 Buffer Pool 中 → 称为 缓存未命中(Cache Miss),需要从磁盘读取数据页到内存,速度慢(磁盘 I/O 比内存访问慢几个数量级)。
1.为什么需要缓存?
- 数据库的数据最终是持久化在磁盘上的。但磁盘(即使是 SSD)的读写速度远远慢于内存:
存储介质典型访问延迟对比
| 存储介质 | 典型访问延迟 |
|---|---|
| CPU 寄存器 | ~1 纳秒 |
| L1/L2 缓存 | ~1–10 纳秒 |
| 主内存(RAM) | ~100 纳秒 |
| NVMe SSD | ~10–100 微秒(= 10,000–100,000 纳秒) |
| 机械硬盘(HDD) | ~5–10 毫秒(= 5,000,000–10,000,000 纳秒) |
内存比磁盘快 100 倍到 10 万倍!
提示
因此,如果每次查询都要去磁盘读数据,数据库性能会非常差。为了解决这个问题,数据库引入了缓冲池(Buffer Pool) —— 一个用内存模拟“高速缓存”的机制。
2.什么是 Buffer Pool(缓冲池)?
定义:
- Buffer Pool 是数据库(如 MySQL InnoDB)在启动时向操作系统申请的一块连续内存区域,用于缓存从磁盘读取的数据页(Data Pages)。
默认大小
- MySQL 中通过 innodb_buffer_pool_size 配置,默认通常是 128MB,但在生产环境中常设为物理内存的 50%~80%。
单位
- 缓存的基本单位是 页(Page),InnoDB 默认页大小为 16KB(可通过配置调整为 4KB、32KB、64KB)。
重要
数据库不是按“行”或“字段”缓存,而是按“页”缓存。
3.缓存命中完整流程(select 为例)
SELECT name FROM users WHERE id = 100;1.定位数据页
- 数据库通过主键索引(B+树)找到id=100所在的数据页编号(比如Page #456)。
2.检查Buffer Pool
- 检查Page #456 是否在Buffer Pool 中。
A 在(Cache Hit )
直接从内存读取该页
解析页内容,提取name字段
返回结果
微秒级B 不在(Cache Miss)
触发一次 磁盘 I/O:从磁盘读取 Page #456 到内存;
将该页放入 Buffer Pool(可能需要淘汰旧页,采用 LRU 算法);
再从内存读取数据;
返回结果
耗时:毫秒级(慢 100~1000 倍)4.影响缓存命中率的关键因素
| 因素 | 说明 | 对命中率的影响 |
|---|---|---|
| Buffer Pool 大小 | 内存越大,能缓存的页越多 | ↑ 内存 → ↑ 命中率 |
| 数据访问局部性 | 热点数据是否集中 | 热点集中 → ↑ 命中率 |
| 表结构设计 | 行太大会减少每页行数 | 行大 → 页少 → ↓ 命中率 |
| 查询模式 | 是否频繁扫描冷数据 | 全表扫描冷数据 → 淘汰热点页 → ↓ 命中率 |
| LRU 算法优化 | InnoDB 使用“改进的 LRU”防止一次性扫描污染缓存 | 合理设计可维持高命中率 |
5.垂直分表如何提升缓存命中率?
原始大表: 100个字段,平均每行5KB,每页仅存在3行
垂直拆分后 :
- 主表:10 个常用字段,每行 200 字节 → 每页可存约 80 行
- 扩展表:90 个不常用/大字段,单独存储
结果:
相同大小的 Buffer Pool,现在能缓存 主表的更多行;
高频查询只访问主表 → 更大概率命中;
冷数据(扩展表)很少加载,不污染 Buffer Pool。重要
这就是“让内存更高效地服务热点数据”的核心思想。
6.总结
| 概念 | 说明 |
|---|---|
| 缓存命中(Cache Hit) | 所需数据页已在内存 Buffer Pool 中,无需磁盘 I/O |
| 缓存未命中(Cache Miss) | 需从磁盘加载数据页到内存,性能开销大 |
| 缓存命中率 | 衡量数据库内存利用效率的关键指标,越高越好 |
| 提升命中率的方法 | 增大 Buffer Pool、优化表结构、聚焦热点数据、避免全表扫描等 |
怎么样优化表结构,见下一篇,优化表结构
版权所有
版权归属:念宇
