mysql索引篇explain命令详解

 更新时间:2022年08月25日 10:20:21   作者:会玩code  
这篇文章主要介绍了mysql索引篇explain命令详解,mysql中的explain命令可以用来查看sql语句是否使用了索引,用了什么索引,有没有做全表扫描,更多相关内容需要的小伙伴可以参考一下

前言

mysql中的explain命令可以用来查看sql语句是否使用了索引,用了什么索引,有没有做全表扫描。可以帮助我们优化查询语句。
explain出来的信息有10列,文章主要介绍type、key、Extra这几个字段。

演示中涉及到的表结构如下:

 CREATE TABLE `dept_desc` (
  `dept_no` char(4) NOT NULL,
  `dept_name` varchar(40) NOT NULL,
  `desc` varchar(255) NOT NULL,
  PRIMARY KEY (`dept_no`)
) ENGINE=InnoDB

CREATE TABLE `dept_emp` (
  `emp_no` int(11) NOT NULL,
  `dept_no` char(4) NOT NULL,
  `from_date` date NOT NULL,
  `to_date` date NOT NULL,
  PRIMARY KEY (`emp_no`,`dept_no`),
  KEY `dept_no` (`dept_no`),
  CONSTRAINT `dept_emp_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees` (`emp_no`) ON DELETE CASCADE,
  CONSTRAINT `dept_emp_ibfk_2` FOREIGN KEY (`dept_no`) REFERENCES `departments` (`dept_no`) ON DELETE CASCADE
) ENGINE=InnoDB

CREATE TABLE `employees` (
  `emp_no` int(11) NOT NULL,
  `birth_date` date NOT NULL,
  `first_name` varchar(14) NOT NULL,
  `last_name` varchar(16) NOT NULL,
  `gender` enum('M','F') NOT NULL,
  `hire_date` date NOT NULL,
  PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB

上面的表都是mysql中测试库的表,需要的同学可以自行去下载。
官方文档:https://dev.mysql.com/doc/employee/en/employees-installation.html

key

sql语句实际执行时使用的索引列,有时候mysql可能会选择优化效果不是最好的索引,这时,我们可以在select语句中使用force index(INDEXNAME)来强制mysql使用指定索引或使用ignore index(INDEXNAME)强制mysql忽略指定索引

type

访问类型,表示数据库引擎查找表的方式,常见的type类型有:all,index,range,ref,eq_ref,const。

all:

全表扫描,表示sql语句会把表中所有表数据全部读取读取扫描一遍。效率最低,我们应尽量避免。

mysql> explain select * from dept_emp;
+----+-------------+----------+------+---------------+------+---------+------+--------+-------+
| id | select_type | table    | type | possible_keys | key  | key_len | ref  | rows   | Extra |
+----+-------------+----------+------+---------------+------+---------+------+--------+-------+
|  1 | SIMPLE      | dept_emp | ALL  | NULL          | NULL | NULL    | NULL | 331570 | NULL  |
+----+-------------+----------+------+---------------+------+---------+------+--------+-------+

index:

  • 全索引扫描,表示sql语句将会把整颗二级索引树全部读取扫描一遍,因为二级索引树的数据量比全表数据量小,所以效率比all高一些。一般查询语句中查询字段为索引字段,且无where子句时,type会为index。如下,mysql确定使用dept_no这个索引,然后扫描整个dept_no索引树得到结果。
mysql> explain select dept_no  from dept_emp;
+----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table    | type  | possible_keys | key     | key_len | ref  | rows   | Extra       |
+----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
|  1 | SIMPLE      | dept_emp | index | NULL          | dept_no | 4       | NULL | 331570 | Using index |
+----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+

range:

部分索引扫描,当查询为区间查询,且查询字段为索引字段时,这时会根据where条件对索引进行部分扫描。

mysql> explain select * from dept_emp  where emp_no > '7';
+----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table    | type  | possible_keys | key     | key_len | ref  | rows   | Extra       |
+----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
|  1 | SIMPLE      | dept_emp | range | PRIMARY       | PRIMARY | 4       | NULL | 165785 | Using where |
+----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+

ref:

出现于where操作符为‘=’,且where字段为非唯一索引的单表查询或联表查询。

// 单表
mysql> explain select * from dept_emp where dept_no = 'd005';
+----+-------------+----------+------+---------------+---------+---------+-------+--------+-----------------------+
| id | select_type | table    | type | possible_keys | key     | key_len | ref   | rows   | Extra                 |
+----+-------------+----------+------+---------------+---------+---------+-------+--------+-----------------------+
|  1 | SIMPLE      | dept_emp | ref  | dept_no       | dept_no | 4       | const | 145708 | Using index condition |
+----+-------------+----------+------+---------------+---------+---------+-------+--------+-----------------------+

// 联表
mysql> explain select * from dept_emp,departments where dept_emp.dept_no = departments.dept_no;
+----+-------------+-------------+-------+---------------+-----------+---------+-------------------------------+------+-------------+
| id | select_type | table       | type  | possible_keys | key       | key_len | ref                           | rows | Extra       |
+----+-------------+-------------+-------+---------------+-----------+---------+-------------------------------+------+-------------+
|  1 | SIMPLE      | departments | index | PRIMARY       | dept_name | 42      | NULL                          |    9 | Using index |
|  1 | SIMPLE      | dept_emp    | ref   | dept_no       | dept_no   | 4       | employees.departments.dept_no |    1 | NULL        |
+----+-------------+-------------+-------+---------------+-----------+---------+-------------------------------+------+-------------+

eq_ref:

出现于where操作符为‘=’,且where字段为唯一索引联表查询

mysql> explain select * from departments,dept_desc where departments.dept_name=dept_desc.dept_name;
+----+-------------+-------------+--------+---------------+-----------+---------+-------------------------------+------+-------------+
| id | select_type | table       | type   | possible_keys | key       | key_len | ref                           | rows | Extra       |
+----+-------------+-------------+--------+---------------+-----------+---------+-------------------------------+------+-------------+
|  1 | SIMPLE      | dept_desc   | ALL    | NULL          | NULL      | NULL    | NULL                          |    1 | NULL        |
|  1 | SIMPLE      | departments | eq_ref | dept_name     | dept_name | 42      | employees.dept_desc.dept_name |    1 | Using index |
+----+-------------+-------------+--------+---------------+-----------+---------+-------------------------------+------+-------------+

const:

出现于where操作符为‘=’,且where字段为唯一索引单表查询,此时最多只会匹配到一行。

mysql> explain select * from departments where dept_no = 'd005';
+----+-------------+-------------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table       | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+-------------+-------+---------------+---------+---------+-------+------+-------+
|  1 | SIMPLE      | departments | const | PRIMARY       | PRIMARY | 4       | const |    1 | NULL  |
+----+-------------+-------------+-------+---------------+---------+---------+-------+------+-------+

综上,单从type字段考虑效率,const > eq_ref > ref > range > index > all.

注意:我们不能仅仅根据type去判断两条sql的执行速度。例如type为range的查询不一定比type为index的全表查询速度要快,还要看具体的sql。因为type为index时,查询是不需要回表操作的,而type为range时,有可能需要回表操作。如sqlA("select dept_no from dept_emp;")和sqlB("select from_date from dept_emp where dept_no > 'd005';"),这个时候sqlB根据where条件扫描索引树后,需要回表查询相应的行数据,以获取from_date的值,而sqlA虽然扫描了整颗索引树,但并不需要回表,所以速度可能会比sqlB更快。

回表操作、索引相关可以阅读mysql索引(覆盖索引,联合索引,索引下推)这篇文章

Extra

extra列会包含一些十分重要的信息,我们可以根据这些信息进行sql优化

  • using index: sql语句没有where查询条件,使用覆盖索引,不需要回表查询即可拿到结果
  • using where: 没有使用索引/使用了索引但需要回表查询且没有使用到下推索引
  • using index && useing where: sql语句有where查询条件,且使用覆盖索引,不需要回表查询即可拿到结果。
  • Using index condition:使用索引查询,sql语句的where子句查询条件字段均为同一索引字段,且开启索引下推功能,需要回表查询即可拿到结果。
  • Using index condition && using where:使用索引查询,sql语句的where子句查询条件字段存在非同一索引字段,且开启索引下推功能,需要回表查询即可拿到结果。
  • using filesort: 当语句中存在order by时,且orderby字段不是索引,这个时候mysql无法利用索引进行排序,只能用排序算法重新进行排序,会额外消耗资源。
  • Using temporary:建立了临时表来保存中间结果,查询完成之后又要把临时表删除。会很影响性能,需尽快优化。

下推索引、覆盖索引相关介绍可阅读mysql索引(覆盖索引,联合索引,索引下推)这篇文章

有时在extra字段中会出现"Impossible WHERE noticed after reading const tables"这种描述。翻看网上资料后,个人发现这是mysql一种很怪的处理方式。

当sql语句满足:

  • 1、根据主键查询或者唯一性索引查询;
  • 2、where操作符为"="时。

在sql语句优化阶段,mysql会先根据查询条件找到相关记录,这样,如果这条数据不存在,实际上就进行了一次全扫描,然后得出一个结论,该数据不在表中。这样对于并发较高的数据库,会加大负载。所以,如果数据不用唯一的话,普通的索引比唯一索引更好用。(文章链接:MySQL慢查询现象解决案例

到此这篇关于mysql索引篇explain命令详解的文章就介绍到这了,更多相关mysql explain命令内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MySQL redo死锁问题排查及解决过程分析

    MySQL redo死锁问题排查及解决过程分析

    被告知在多实例场景下 MySQL Server hang 住,无法测试下去,原生版本不存在这个问题,而新版本上出现了这个问题,不禁心头一颤,心中不禁感到奇怪,还好现场环境还在,为排查问题提供了一个好的环境,随即便投入到紧张的问题排查过程当中
    2016-10-10
  • MySQL数据库迁移data文件夹位置详细步骤

    MySQL数据库迁移data文件夹位置详细步骤

    这篇文章主要介绍了MySQL数据库迁移data文件夹详细步骤,需要的朋友可以参考下
    2014-03-03
  • Mysql中校对集utf8_unicode_ci与utf8_general_ci的区别说明

    Mysql中校对集utf8_unicode_ci与utf8_general_ci的区别说明

    一直对utf8_unicode_ci与utf8_general_ci这2个校对集很迷惑,今天查了手册有了点眉目。不过对中文字符集来说采用utf8_unicode_ci与utf8_general_ci时有何区别还是不清楚
    2012-03-03
  • mysql自动增量备份的实例方法(本地备份与远程备份)

    mysql自动增量备份的实例方法(本地备份与远程备份)

    mysql自动增量备份的例子(本地备份与远程备份),有需要的朋友可以参考下
    2013-02-02
  • MySQL分表和分区的具体实现方法

    MySQL分表和分区的具体实现方法

    这篇文章主要介绍了MySQL分表和分区的具体实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-06-06
  • ssm框架如何调用mysql存储过程

    ssm框架如何调用mysql存储过程

    这篇文章主要介绍了ssm框架如何调用mysql存储过程,首先是建表,创建存储过程,本文结合示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-05-05
  • MySQL实战窗口函数SQL分析班级学生考试成绩及生活消费

    MySQL实战窗口函数SQL分析班级学生考试成绩及生活消费

    这篇文章主要为大家介绍了MySQL实战,利用窗口函数SQL来分析班级学生的考试成绩及生活消费的示例过程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2021-10-10
  • MYSQL行列转置方式

    MYSQL行列转置方式

    本文介绍了如何使用MySQL和Navicat进行列转行操作,首先,创建了一个名为`grade`的表,并插入多条数据,然后,通过修改查询SQL语句,使用`CASE`和`IF`函数将列转换为行,总结指出,`SUM`可以替换为`MAX`、`MIN`、`AVG`等聚合函数,并且在查询中需要对普通字段进行分组
    2025-01-01
  • MySQL9.0.1安装教程的实现示例

    MySQL9.0.1安装教程的实现示例

    本文主要介绍了MySQL软件的下载、解压、环境变量配置、初始化及启动、登录与密码设置等步骤,详细说明了每一步的操作方法,感兴趣的可以了解一下
    2024-10-10
  • mysql密码忘记怎么办

    mysql密码忘记怎么办

    mysql密码忘记怎么办?卸载重装?这篇文章主要为大家详细介绍了不卸载也能重新设置密码的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-02-02

最新评论