mysql索引篇explain命令详解
作者:会玩code 发布时间:2024-01-22 10:38:17
前言
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慢查询现象解决案例)
来源:https://www.jianshu.com/p/8cc547d05478


猜你喜欢
- asp之字符串函数示例用字符串函数对字符串进行截头去尾、大小写替换等操作。函数语 * 能LenLen(string|varname)返回字符串
- 内置300余汉字点阵.纯ASP实现汉字验证码.不读数据库.多种属性自由调节,其中包括:生成的图片长和宽,字符数,背景显示效果(渐变,杂色,固
- 组件值校验,即在组件值变化时判断是否满足校验逻辑,若不满足校验逻辑,可以拿到校验错误信息进行错误提示或其他逻辑处理。声明 valueVali
- 1、ComboBox的基础属性# -*- encoding=utf-8 -*-import tkinterfrom tkinter impo
- 运行环境IDE丨pycharm版本丨Python3.6系统丨Windows实现目的与思路目的实现对腾讯视频目标url的解析与下载,由于第三方
- 很多人看到PHP就以为是程序员,就以为钱很多(虽然是事实),但是也要考虑下自己是不是适合这一行,知道PHP是什么吗?PHP都有什么样的功能,
- Matplotlib编程实现import matplotlib.pyplot as pltimport numpy as npfrom ma
- 回想下,在 Python 中编程时,你是否曾经需要检查某个可迭代对象(如列表)中的任何元素或所有元素的计算结果是否为True?假设,我们要判
- 一, 创建用户: 命令:CREATE USER 'usern
- Windows Server 2003系统是现在很流行的服务器操作系统,许多网站都用它来做。但是如何保证服务器的相对安全,这个只要进行一些简
- 报错代码粉丝群里面的一个小伙伴想用requests爬虫,然后遍历Xpath定位的数据列表的时候,发生了报错(当时他心里瞬间凉了一大截,跑来找
- 本文主要介绍了Python3 内置函数,分享给大家,具体如下:内置函数以下代码以Python3.6.1为例#coding=utf-8# bu
- Python 语言的优势在于其功能强大,可以用于网络数据采集、数据分析等各种应用场景。本篇文章将介绍如何使用 Python 获取网络数据、使
- 本文实例讲述了Python实现PS滤镜特效之扇形变换效果。分享给大家供大家参考,具体如下:这里用 Python 实现 PS 滤镜中的一种几何
- 引言在使用SqlServer Express 版本的时候发现,这个版本不支持通过数据库的代理方式进行数据库的维护。解决方案使用SQL语句加w
- 在众多代码编辑工具中,我最喜欢的就是微软的vscode。首先它十分轻便,不吃硬件,运行非常顺畅;其次是其各种各样的插件使得编程效率蹭蹭地往上
- 一、Tornado简介Tornado是一个使用Python编写的高效、非阻塞的web服务器软件和网络库。它被设计用于处理数以千计的并发连接,
- 前言这段时间刚刚学习了一段时间的Python,加上自己是做iOS开发的,就想着用Python来做一个自动化打包,可以自动完成打包,上传到蒲公
- 今天分享的这篇文章,文字不多,代码为主。绝对干货,童叟无欺,主要分享了提升 Python 性能的 20 个技巧,教你如何告别慢Python。
- mysql建表test;安装logstash(跟es版本一致)# 下载wget https://repo.huaweicloud.com/l