关于mysql索引类型总结
这里主要拿innob分析,就目前来看,默认都是用innodb, myisam 现在使用很少, 过去总是一直说这个索引,其实呢,按适用类型来分的话,就两种:
- 主键索引(聚簇索引(Clustered Index))
- 辅助索引(辅助索引包含很多: 前缀索引 组合索引 全文索引等)
主键索引的结构:
- 索引数据和表的行数据存放在一起。
- 主键索引的叶子节点包含了完整的行数据(数据页)。
如下:
[ 50 ] ← 内部节点(索引键)
/ \
+----------------+ +---------------------+
| [10, 20, 30] | | [50, 70, 90] | ← 叶子节点(含整行数据)
+----------------+ +---------------------+
↓ ↓
+-----------------+ +-----------------+
| PK=10, Row1 | | PK=50, Row4 |
| name: 'A' | | name: 'D' |
| age: 20 | | age: 30 |
+-----------------+ +-----------------+
+-----------------+ +-----------------+
| PK=20, Row2 | | PK=70, Row5 |
| name: 'B' | | name: 'E' |
| age: 25 | | age: 22 |
+-----------------+ +-----------------+
+-----------------+ +-----------------+
| PK=30, Row3 | | PK=90, Row6 |
| name: 'C' | | name: 'F' |
| age: 28 | | age: 24 |
+-----------------+ +-----------------+
辅助索引的结构:
- 辅助索引的叶子节点 只包含索引列 + 主键列
- 并不包含整行数据(与聚簇索引不同!)
- 查询时,如果你要获取其他字段,就必须 “回表”
如下:
✅ 场景设定(继续使用原表结构):
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50),
age INT,
INDEX idx_name(name) -- 辅助索引!
);
| id | name | age |
|---|---|---|
| 10 | Alice | 22 |
| 20 | Bob | 25 |
| 30 | Carol | 28 |
| 40 | Dave | 30 |
🎯 图一:辅助索引结构图(idx_name)
[ Carol ]
/ \
+----------------+ +-------------------+
| Alice | Bob | | Carol | Dave | ← 叶子节点
+----------------+ +-------------------+
↓ ↓
+-------------+ +-------------+
| name=Alice | | name=Carol |
| PK=10 | | PK=30 |
+-------------+ +-------------+
| name=Bob | | name=Dave |
| PK=20 | | PK=40 |
+-------------+ +-------------+
←←←←←←←←←← 双向链表连接 →→→→→→→→→→
🔁 图二:辅助索引 → 回表过程
执行 SQL:
SELECT age FROM users WHERE name = 'Carol';
执行流程图 👇
Step 1:
🔎 辅助索引 idx_name 查 name='Carol'
↓
→ 定位到主键值 PK=30
Step 2:
🔁 回到主键 B+树(聚簇索引)
↓
→ 从聚簇索引叶子节点中根据 PK=30 取出整行数据(包含 age 字段)
Step 3:
🎯 返回结果:age=28
🧠 注意:如果 SELECT 中已经包含 name(即索引字段),那就不用回表。
二者对比, 聚簇索引 vs 辅助索引:
| 特性 | 聚簇索引(主键) | 辅助索引(非主键字段) |
| -------- | -------------- | ------------------- |
| 叶子节点内容 | ✅ 主键值 + 整行数据 | ✅ 索引字段 + 主键值(无其他字段) |
| 是否需要回表 | ❌ 不需要(行数据在叶子中) | ✅ 需要(除非查询字段只包含索引字段) |
| 查找效率 | 高 | 稍慢(需要两次树查找) |
| 索引字段可否重复 | 不可重复(主键) | 可重复(索引允许重复) |
✅ 优化建议:
| 场景 | 优化方式 |
| -------------------- | -------------------------- |
| 经常根据 name 查询,并只查 id | ✅ 使用覆盖索引,避免回表 |
| 经常根据 name 查询 + 查 age | 考虑建立**联合索引** (`name, age`) |
| 查询字段包含非索引列 | ✅ 回表不可避免,考虑是否值得 |
| name 很长,性能低 | 可用 `name(10)` 前缀索引 + hash |
📣 你还可以用 EXPLAIN FORMAT=JSON 看 MySQL 是否进行了回表操作,字段是:
"using_index": true
"using_index_condition": true
额外说明:
MyISAM 引擎:主键索引和辅助索引都是普通的B树索引,数据和索引是分开的。
B树索引的含义:
MyISAM 的索引结构是 B树(而不是 B+树),也是一种平衡多路查找树。
索引文件里记录的是索引键值和指向数据文件中对应行的指针(偏移量)。
InnoDB 引擎:主键索引是聚簇索引,辅助索引的叶子节点存的是主键值。
