一、索引基础概念
1. 索引是什么?
- 定义:索引是帮助MySQL高效获取数据的有序数据结构,类似书籍的目录。
- 核心作用:减少磁盘I/O次数,提升查询速度(以空间换时间)。
2. 索引的优缺点
优点 | 缺点 |
---|
加速查询(WHERE、JOIN、ORDER BY) | 占用磁盘空间 |
保证数据唯一性(唯一索引) | 增删改操作变慢(维护索引) |
加速表间连接 | 过多索引增加优化器选择成本 |
二、索引数据结构
1. B+树(默认结构)
-
特点:
- 多叉平衡树,层数少(3~4层可存千万级数据)。
- 叶子节点存储数据(InnoDB存主键值或完整数据行)。
- 叶子节点通过指针串联,支持范围查询。
-
B+树 vs B树:
对比项 | B+树 | B树 |
---|
数据存储位置 | 仅叶子节点存数据 | 所有节点均可存数据 |
查询稳定性 | 稳定(查询路径长度一致) | 不稳定 |
范围查询 | 高效(叶子节点链表连接) | 需中序遍历 |
2. 哈希索引(MEMORY引擎)
- 特点:
- 基于哈希表,精确查询O(1)时间复杂度。
- 不支持范围查询和排序,仅适合等值查询。
三、索引类型与使用场景
1. 索引分类
类型 | 说明 | 示例 |
---|
主键索引 | 唯一标识,不允许NULL | PRIMARY KEY (id) |
唯一索引 | 列值唯一,允许NULL | UNIQUE KEY (email) |
普通索引 | 无唯一性约束 | INDEX idx_name (name) |
联合索引 | 多列组合索引 | INDEX idx_age_name (age,name) |
全文索引 | 文本内容分词搜索(InnoDB支持) | FULLTEXT (content) |
2. 聚簇索引 vs 非聚簇索引
对比项 | 聚簇索引(InnoDB) | 非聚簇索引(MyISAM) |
---|
数据存储 | 索引与数据文件绑定 | 索引与数据文件分离 |
主键查询 | 直接定位数据行 | 需回表查询(二次查找) |
叶子节点内容 | 存储完整数据行 | 存储数据行的物理地址 |
四、索引优化核心原则
1. 最左前缀原则
- 定义:联合索引中,查询条件需从最左列开始,且不能跳过中间列。
- 示例:
索引 (age, name, city)
- ✅ 有效:
WHERE age=20 AND name='Tom'
- ❌ 无效:
WHERE name='Tom' AND city='Beijing'
(未使用age)
2. 覆盖索引
3. 索引失效场景
场景 | 示例 | 解决方案 |
---|
对索引列运算或函数 | WHERE YEAR(create_time)=2023 | 避免函数,改用范围查询 |
隐式类型转换 | WHERE id = '100' (id为INT) | 保持类型一致 |
OR连接非索引列 | WHERE age=20 OR address='上海' | 拆分查询或为address加索引 |
LIKE左模糊匹配 | WHERE name LIKE '%John%' | 改用右模糊(John% ) |
五、EXPLAIN执行计划分析
1. 关键字段解读
字段 | 说明 | 优化方向 |
---|
type | 访问类型(性能排序):system > const > ref > range > index > ALL | 尽量达到 range 以上 |
key | 实际使用的索引 | 确保命中索引 |
rows | 预估扫描行数 | 减少扫描量 |
Extra | 额外信息(如 Using index ) | 利用覆盖索引 |
2. 示例分析
EXPLAIN SELECT * FROM users WHERE age=25 ORDER BY name;
- 若
type=ALL
且 key=NULL
:说明未命中索引,需为 age
或 (age, name)
建索引。
六、面试题
1. 为什么用B+树而不用B树或哈希表?
- B+树:适合范围查询,减少磁盘I/O(非叶子节点只存键,可容纳更多分支)。
- 哈希表:仅适合等值查询,无法排序和范围查询。
2. 如何优化慢查询?
- 使用
EXPLAIN
分析执行计划。 - 为WHERE、JOIN、ORDER BY字段添加索引。
- 避免索引失效场景(如函数操作)。
- 考虑分库分表或读写分离(数据量过大时)。
3. 什么是回表查询?如何避免?
- 回表:通过普通索引查到主键后,再通过主键索引查找数据行。
- 避免:使用覆盖索引(查询字段均在索引中)。
4. 主键为什么要用自增ID?
- B+树插入效率:自增ID保证新数据顺序插入叶子节点,避免页分裂。