Explain详解与索引优化最佳实践

目录

目标

  • 掌握EXPLAIN关键字用法,能读懂EXPLAIN执行计划含义,通过执行计划分析 SQL 查询的性能瓶颈。
  • 理解EXPLAIN两个变种extended和partitions的功能与使用场景
  • 掌握 MySQL 索引使用的最佳实践,能识别导致索引失效的常见场景,并能针对性优化 SQL 语句
  • 能结合EXPLAIN执行计划和索引优化规则,独立完成慢 SQL 的分析与优化

EXPLAIN列详解

sql 复制代码
示例表:
DROP TABLE IF EXISTS `actor`; 
CREATE TABLE `actor` (
  `id` int(11) NOT NULL,
  `name` varchar(45) DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `actor` (`id`, `name`, `update_time`) VALUES (1,'a','2017-12-22 15:27:18'), (2,'b','2017-12-22 15:27:18'), (3,'c','2017-12-22 15:27:18');

DROP TABLE IF EXISTS `film`;
CREATE TABLE `film` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `film` (`id`, `name`) VALUES (3,'film0'),(1,'film1'),(2,'film2');

DROP TABLE IF EXISTS `film_actor`;
CREATE TABLE `film_actor` (
  `id` int(11) NOT NULL,
  `film_id` int(11) NOT NULL,
  `actor_id` int(11) NOT NULL,
  `remark` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_film_actor_id` (`film_id`,`actor_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `film_actor` (`id`, `film_id`, `actor_id`) VALUES (1,1,1),(2,1,2),(3,2,1);

通过EXPLAIN关键字可以清楚看出SQL的分析情况

sql 复制代码
explain select * from actor;

id

SQL执行顺序,id越大先执行,id相同从上往下执行,id为NULL最后执行。

select_type

对应行是简单还是复杂查询

  • simple:简单查询,不包含子查询和union
  • primary:复杂查询中最外层的 select
  • subquery:包含在 select 后的子查询
  • derived:包含在 from 子句中的子查询。MySQL会将结果存放在一个临时表中
sql 复制代码
set session optimizer_switch='derived_merge=off';   #关闭mysql5.7新特性对衍生表的合并优化
explain select (select 1 from actor where id = 1) from (select * from film where id = 1) der;

table

正在访问的表名

partitions

分区表,几乎不用

type

此列表示MYSQL如何去查询表中的行,从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL,一般要优化到range,最好是ref

NULL:此情况出现较少,在分析阶段就能分解查询语句,比如直接在索引上求最小值

const, system:最多一行数据,像是查常量一样

eq_ref:primary key 或 unique key 索引的所有部分被连接使用 ,最多只会返回一条符合条件的记录

ref:相比 eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前缀

range:范围扫描通常出现在 in(), between ,> ,<, >= 等操作中。使用一个索引来检索给定范围的行

index:扫描全索引就能拿到结果,一般是扫描某个二级索引,这种扫描不会从索引树根节点开始快速查找,而是直接对二级索引的叶子节点遍历和扫描,速度还是比较慢的,这种查询一般为使用覆盖索引,二级索引一般比较小,所以这种通常比ALL快一些。

ALL:即全表扫描,扫描你的聚簇索引的所有叶子节点。通常情况下这需要增加索引来进行优化了。

possible_keys列

这一列显示查询可能使用哪些索引来查找。

explain 时可能出现 possible_keys 有列,而 key 显示 NULL 的情况,这种情况是因为表中数据不多,mysql认为索引对此查询帮助不大,选择了全表查询。

key列

这一列显示mysql实际采用哪个索引来优化对该表的访问。

key_len列

显示了mysql在索引里使用的字节数,通过这个值可以算出具体使用了索引中的哪些列

ref列

显示了在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量),字段名(例:film.id

rows列

mysql估计要读取并检测的行数,注意这个不是结果集里的行数

filtered 列

百分比的值,rows * filtered/100 可以估算出将要和 explain 中前一个表进行连接的行数

extra列

  • Using index:使用覆盖索引
  • Using where:使用 where 语句来处理结果,并且查询的列未被索引覆盖
  • Using index condition:查询的列不完全被索引覆盖,where条件中是一个前导列的范围
  • Using temporary:mysql需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的,首先是想到用索引来优化
相关推荐
计算机毕设vx_bysj686912 小时前
【免费领源码】77196基于java的手机银行app管理系统的设计与实现 计算机毕业设计项目推荐上万套实战教程JAVA,node.js,C++、python、大屏数据可视化
java·mysql·智能手机·课程设计
吴声子夜歌13 小时前
ES6——正则的扩展详解
前端·mysql·es6
xixingzhe213 小时前
Mysql统计空间增量
数据库·mysql
程序员萌萌13 小时前
Java之mysql实战讲解(三):聚簇索引与非聚簇索引
java·mysql·聚簇索引
cozil14 小时前
记录mysql创建数据库未指定字符集引发的问题及解决方法
数据库·mysql
AC赳赳老秦14 小时前
OpenClaw数据库高效操作指南:MySQL/PostgreSQL批量处理与数据迁移实战
大数据·数据库·mysql·elasticsearch·postgresql·deepseek·openclaw
ego.iblacat15 小时前
Python 连接 MySQL 数据库
数据库·python·mysql
阿丰资源16 小时前
SpringBoot+MySQL+MyBatis-Plus+Vue前后端分离仓库管理系统 (附资料)
spring boot·mysql·mybatis
阿华田51217 小时前
MySQL性能优化大全
数据库·mysql·性能优化
被摘下的星星17 小时前
MySQL 别名使用规则详解
数据库·mysql