MySQL深度解析(第二篇)索引原理、SQL优化、执行计划与慢查询
标签:MySQL索引,B+树,explain,SQL优化,慢查询
前言
第一篇搞定了InnoDB底层、事务、MVCC。开发工作中最常打交道就是索引,大部分线上性能问题,根源都是索引设计不合理、写出低效SQL。本篇重点讲解InnoDB聚簇索引原理、索引分类、索引失效场景、Explain执行计划,慢查询排查,以及SQL优化实战技巧。
一、InnoDB聚簇索引(主键索引)
InnoDB使用聚簇索引:表数据本身按照主键有序存放在B+树叶子节点,索引和数据在一起。
- 叶子节点:完整的一行数据,并且按主键排序
- 非叶子节点:只存放主键值+页指针,用于索引检索
对比MyISAM非聚簇:索引和数据文件分开,索引叶子节点存储数据行地址。
聚簇索引 vs 二级索引
| 索引类型 | 叶子节点存储内容 | 查询流程 | 特点 |
|---|---|---|---|
| 聚簇索引(主键索引) | 完整行数据 | 主键查询直接拿到行数据 | 主键必须有序;主键不宜过大,二级索引会变大 |
| 二级索引(普通索引) | 主键值 | 查到主键,再回表去主键索引读取完整数据(回表) | 联合索引最左前缀原则,减少回表可以使用覆盖索引 |
覆盖索引:二级索引包含查询所需要全部字段,不需要回表,性能极高。
二、B+树索引特点
InnoDB索引底层是B+树,不是二叉树、B树。
- 所有数据都在叶子节点,非叶子只存索引键,树矮,IO次数少
- 叶子节点之间用双向链表串联,范围查询(> < between,order by)非常高效
- 节点大小等于InnoDB页(默认16KB),一页可以存大量索引条目,树高度一般2~4层
三、索引分类
- 主键索引PRIMARY:聚簇索引,唯一非空,一张表只能一个
- 唯一索引UNIQUE:索引列不能重复,可以为NULL
- 普通索引INDEX:普通二级索引,允许重复和NULL
- 联合索引(复合索引) :多个字段组合索引,遵循最左前缀原则
- 全文索引FULLTEXT:长文本分词检索,不适合模糊like '%xxx%'
索引设计黄金原则
- 联合索引,把区分度高、查询频率高的字段放前面
- 尽量使用覆盖索引,避免回表
- 索引字段尽量小,不要在大字符串、大文本建索引
- 不要在低区分度字段(性别、状态)单独建索引
- 索引不是越多越好,索引会降低写入性能(增删改需要维护B+树)
四、索引失效常见场景
- 索引列做函数运算、隐式类型转换
- like 以%开头
like '%abc',无法走B+树索引 - or两边字段,有一个没有索引
- 违反最左前缀原则,跳过前面索引列
- MySQL优化器判断全表扫描比索引更快,主动放弃索引
五、Explain执行计划详解
使用 explain select xxx; 查看SQL执行计划,判断是否命中索引。
| 字段 | 含义 | 关注点 |
|---|---|---|
| id | 查询序号,子查询、关联查询标识 | id越大优先级越高 |
| select_type | 查询类型,SIMPLE简单查询、SUBQUERY子查询、DERIVED派生表 | 尽量避免DEPENDENT SUBQUERY相关子查询 |
| table | 当前访问哪张表 | |
| type | 访问类型,性能从优到劣:system>const>eq_ref>ref>range>index>ALL | 目标至少range/ref,ALL代表全表扫描,需要优化 |
| possible_keys | 理论可用索引 | 仅参考,不一定实际使用 |
| key | 实际选用索引 | NULL代表没用到索引 |
| key_len | 索引使用字节长度 | 判断联合索引使用多少列 |
| ref | 索引匹配条件,哪些列/常量和索引对比 | |
| rows | 预估扫描行数 | 越小越好,评估扫描代价 |
| Extra | 额外信息,核心重点 | Using filesort 文件排序;Using temporary临时表;Using index覆盖索引;Using where |
重点警告:
Using filesort(文件排序)、Using temporary(临时表)属于高危性能信号,代表MySQL无法利用索引排序,需要额外内存/磁盘排序,大数据集性能很差。
六、慢查询日志
慢查询日志用来捕获执行超过阈值的SQL,是线上排查性能问题的利器。
核心参数:
- slow_query_log:开启/关闭慢日志
- long_query_time:慢查询阈值(单位秒,默认10s)
- log_queries_not_using_indexes:记录没有使用索引的SQL
生产建议:long_query_time 设置为1s,开启记录未走索引SQL,定期分析慢日志。
七、SQL优化通用思路
- 先用explain查看执行计划,定位是否全表扫描、文件排序、临时表
- 优先建立合适索引,利用覆盖索引减少回表
- 避免select *,只查询业务需要字段,减少数据传输,更容易触发覆盖索引
- 减少子查询,优先使用JOIN;JOIN字段保证类型一致,建立索引
- 分页优化:大offset分页,不要limit 100000,10,推荐主键id过滤
where id>xxx limit 10 - 减少大事务,大事务持有锁时间长,容易锁等待
第二篇小结
本篇掌握B+树索引、聚簇索引、联合索引最左前缀、索引失效场景,看懂explain执行计划,慢查询定位方法和SQL优化方案。
索引优化是开发高频工作,但索引只能解决查询性能。第三篇我们学习主从复制、MGR、高可用架构,锁详解,运维参数调优,线上故障排查和最佳实践。