当前位置: 首页 > news >正文

聚簇索引回表与覆盖索引

一句话

InnoDB 的表本身就是一棵以主键为 key 的 ​B+ 树(聚簇索引)​。普通索引的叶子节点存的是主键值,查数据时需要​回表​。覆盖索引让查询不回表,是性能优化的核心手段。


聚簇索引(Clustered Index)

什么是聚簇索引?

InnoDB 的表 = 一棵以主键为 key 的 B+ 树。这棵树就是聚簇索引。

B+ 树的 key = 主键 id B+ 树的叶子节点 = 整行数据(id, name, age, ...) 所以: SELECT * FROM user WHERE id = 100; → 从 B+ 树根节点开始,3 层就到叶子节点,直接拿到整行数据 ✅

主键索引的叶子节点就是数据本身。找到了 key 就找到了整行数据。

聚簇索引的特性

① 一个表只能有一个聚簇索引 因为数据在磁盘上只能按一种顺序物理排列 ② 主键就是聚簇索引 CREATE TABLE user (id BIGINT PRIMARY KEY, ...) → id 就是聚簇索引 ③ 没有主键怎么办? MySQL 优先级: 有主键 → 主键做聚簇索引 ✅ 没主键 → 第一个 NOT NULL 唯一索引 → 聚簇索引 都没有 → 隐藏的 ROW_ID → 聚簇索引

为什么不推荐 UUID 做主键?

自增 ID(bigint): 新数据 → key 递增 → 追加到 B+ 树最右边 → 不发生页分裂 → 性能好 ✅ UUID(字符串): 新数据 → key 随机 → 插入到 B+ 树中间 → 页分裂频繁 → 性能差 ❌ 分布式场景替代方案:雪花算法 - 64 位 long,8 字节(和 bigint 一样) - 按时间递增,追加到 B+ 树末尾 - 全局唯一

非聚簇索引(普通索引)

普通索引的叶子节点存什么?

CREATEINDEXidx_ageONuser(age);
idx_age 这棵 B+ 树: 内部节点:存 age(路标) 叶子节点:存 age + 主键 id(不是整行数据) 所以: SELECT * FROM user WHERE age = 25; ① 走 idx_age → 找到叶子节点 → 拿到主键 id=100 ② 拿 id=100 去聚簇索引再查一次 → 拿到整行数据 ③ 第②步就叫"回表"

回表(Back to Table)

什么是回表?

普通索引不存整行数据,只存主键 id。 查到主键 id 后,还需要再去聚簇索引查一次才能拿到整行数据。 这第二次查询就叫"回表"。 回表的代价:多一次 B+ 树查找(多几次磁盘 I/O)

怎么避免回表?

用覆盖索引。

-- 假设有一个联合索引:idx_age_name(age, name)-- ❌ 会回表SELECT*FROMuserWHEREage=25;-- 因为 * 包含了 age、name 之外的其他字段-- 普通索引的叶子节点没有这些字段 → 必须回表-- ✅ 不回表(覆盖索引)SELECTage,nameFROMuserWHEREage=25;-- age 和 name 都在 idx_age_name 的叶子节点里 → 直接返回 ✅

覆盖索引

定义:查询的字段全部包含在索引的叶子节点中,不需要回表。 覆盖索引 = 索引"覆盖"了查询所需的全部字段 例子: 表:user(id, name, age, address) 索引:idx_age_name(age, name) SELECT age, name FROM user WHERE age = 25 → age 和 name 都在 idx_age_name 的索引树里 → MySQL 只走索引树,不回表 ✅

Oracle/达梦 vs MySQL 索引差异

MySQL InnoDB: 聚簇索引叶子节点 → 存整行数据 普通索引叶子节点 → 存主键 id 回表:用主键 id 再去聚簇索引查一次 Oracle/达梦: 主键索引叶子节点 → 存 ROWID(物理地址) 普通索引叶子节点 → 存 ROWID(物理地址) 回表:用 ROWID 直接定位到数据行(一次寻址) 所以 Oracle/达梦也需要回表,但 ROWID 是物理地址, 定位数据比 MySQL 的"主键 id 二次查询"更快一步。

🎙 面试回答模板

"InnoDB 的表本身就是一棵以主键为 key 的 B+ 树(聚簇索引)。 一个表只能有一个聚簇索引,因为数据只能按一种顺序物理排列。 普通索引的叶子节点存的是主键值,查数据时需要先走普通索引 拿到主键 id,再去聚簇索引查整行数据——这叫回表。 避免回表的方法是覆盖索引:把查询中用到的字段都包含在索引里。 这样索引树本身就包含了所有需要的数据,不用回表。 这也是为什么建联合索引时,除了条件字段,还要考虑 select 的字段。"

参考来源

  • 《MySQL 技术内幕:InnoDB 存储引擎》
  • MySQL 官方文档:Clustered and Secondary Indexes
http://www.jsqmd.com/news/1135235/

相关文章:

  • STM32L4与74HC32实现低功耗多键盘管理方案
  • 4#深萃--全流程深度解析
  • DDIC 的未来,传统 ABAP Dictionary 向 CDS 原生数据模型的迁移路线
  • 【VTG】 VTG-LLM: Integrating Timestamp Knowledge into Video LLMs for Enhanced Video Temporal Ground
  • OpenBMC:Redfish 管理接口
  • Unity 物理系统与 C# 脚本交互:3 种控制小球移动方案的性能与手感对比
  • 3种方法解决Navicat试用到期问题:Mac用户的终极重置指南
  • Windows系统文件autopilot.dll丢失找不到问题解决
  • 掌握Loop Engineering:让AI持续自主完成任务,小白程序员必备收藏指南!
  • 把 Claude Code auto memory 当成一套工程治理开关来看
  • 跨手机微信记录转移教程,再也不怕聊天记录清空避雷省钱向
  • WSA-Pacman:告别ADB命令,Windows安卓应用管理的革命性解决方案
  • Midscene.js:视觉驱动UI自动化,告别脆弱选择器
  • 新手跨境电商独立站搭建工具实测对比:BBWEYY/比文云/Framer/Prismic(2026年7月更新)含零代码SAAS、AI编程、源码定制交付
  • 基于DGN的电工基础-1
  • YOLOv11【第十章:前沿演进与跨界融合篇·第29节】元宇宙 YOLOv11 商业化落地全路径!
  • Scikit-learn 1.5.0 波士顿房价预测:7种回归模型R2对比与过拟合分析
  • 【VTG】T2SGrid: Temporal-to-Spatial Gridification for VTG
  • 3个技巧解决跨平台多媒体开发难题:SFML实战指南
  • 基于SGM62111和PIC18F57Q43的智能DC-DC降压电源设计
  • 05-服务端渲染与元框架——06. API Routes - 服务端 API
  • 洛谷 P3389:[模板] 高斯消元法 ← 高斯-约旦消元法(Gauss-Jordan Elimination)
  • 【RAG】RAG检索增强生成(上)——文档解析与向量数据库实战
  • 固定底座设计2
  • 一篇焦虑文案,ChatGPT 说还行,271 个 AI 用户却想点踩
  • 5分钟掌握抖音无水印下载:免费批量下载工具终极指南
  • 多设备传动改造:盖茨工业皮带的工程应用经验复盘
  • UC Berkeley | 只用单目RGB视频,就能搞定机器人灵巧动作?
  • ICM-42688-P与PIC24FV16KA302在工业自动化中的应用解析
  • 最新短视频素材分发系统源码 全开源版本