2.3 KiB
2.3 KiB
title, date, category, tags, excerpt
| title | date | category | tags | excerpt | |||
|---|---|---|---|---|---|---|---|
| MySQL 索引优化实战:从 EXPLAIN 到索引设计 | 2026-05-24 | 数据库 |
|
深入讲解 B+ 树索引结构、覆盖索引、索引下推、联合索引最左前缀原则。 |
一、B+ 树索引结构
1.1 为什么选择 B+ 树
MySQL InnoDB 存储引擎选择 B+ 树作为索引结构,原因如下:
- 所有数据存储在叶子节点,非叶子节点只存键值
- 叶子节点通过双向链表连接,支持范围查询
- 树的高度通常在 2-4 层,IO 次数可控
1.2 聚簇索引 vs 二级索引
聚簇索引:叶子节点存储完整行数据,一个表只能有一个。
二级索引:叶子节点存储主键值,查询需要回表。
-- 查看索引使用情况
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
二、EXPLAIN 分析
2.1 关键字段解读
| 字段 | 含义 | 期望值 |
|---|---|---|
| type | 访问类型 | const > ref > range > index > ALL |
| key | 实际使用的索引 | 不应为 NULL |
| rows | 扫描行数估计 | 越小越好 |
| Extra | 额外信息 | Using index 表示覆盖索引 |
2.2 常见优化案例
-- 案例1:避免索引失效
-- ❌ 函数导致索引失效
SELECT * FROM orders WHERE DATE(created_at) = '2026-01-01';
-- ✅ 范围查询
SELECT * FROM orders
WHERE created_at >= '2026-01-01' AND created_at < '2026-01-02';
三、索引设计原则
3.1 最左前缀原则
联合索引 (a, b, c) 相当于创建了三个索引:
(a)(a, b)(a, b, c)
CREATE INDEX idx_name_age_city ON users(name, age, city);
-- 可以走索引
SELECT * FROM users WHERE name = '张三';
SELECT * FROM users WHERE name = '张三' AND age = 25;
-- 不能走索引(跳过了 name)
SELECT * FROM users WHERE age = 25;
3.2 覆盖索引
查询的所有列都包含在索引中,避免回表:
CREATE INDEX idx_email_name ON users(email, name);
-- Using index(覆盖索引)
SELECT email, name FROM users WHERE email = 'test@example.com';
四、总结
- 索引不是越多越好,每个索引都会增加写操作成本
- 定期分析慢查询日志
- 使用
EXPLAIN验证索引是否被正确使用 - 联合索引遵循最左前缀原则