Mysql系列-性能优化神器EXPLAIN使用介绍及分析

简介

 MySQL 提供了一个 EXPLAIN 命令, 它可以对 SELECT 语句进行分析, 并输出 SELECT 执行的详细信息, 以供开发人员针对性优化。

 EXPLAIN 命令用法十分简单, 在 SELECT 语句前加上 Explain 就可以了, 例如:

EXPLAIN SELECT * from user_info WHERE id < 300;

下面是我结合我自己创建的表以及执行相关sql语句总结的相关知识点。

准备

为了接下来方便演示 EXPLAIN 的使用, 首先我们需要建立两个测试用的表, 并添加相应的数据:

DROP TABLE IF EXISTS `customers`;
CREATE TABLE `customers`  (
  `customerNumber` int(11) NOT NULL,
  `customerName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `contactLastName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `contactFirstName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `phone` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `addressLine1` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `addressLine2` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `city` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `state` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `postalCode` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `country` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `salesRepEmployeeNumber` int(11) NULL DEFAULT NULL,
  `creditLimit` decimal(10, 2) NULL DEFAULT NULL,
  PRIMARY KEY (`customerNumber`) USING BTREE,
  INDEX `salesRepEmployeeNumber`(`salesRepEmployeeNumber`) USING BTREE,
  INDEX `customers_idx_combine_1`(`customerName`, `phone`, `customerNumber`) USING BTREE,
  CONSTRAINT `customers_ibfk_1` FOREIGN KEY (`salesRepEmployeeNumber`) REFERENCES `employees` (`employeeNumber`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

创建表成功后,插入一些测试数据。

EXPLAIN 输出格式

EXPLAIN 命令的输出内容大致如下:

mysql> EXPLAIN SELECT * FROM customers WHERE customerName=‘Herkku Gifts‘ AND phone=‘+47 2267 3215‘ AND customerNumber=167;
+----+-------------+-----------+------------+-------+---------------------------------+---------+---------+-------+------+----------+-------+
| id | select_type | table     | partitions | type  | possible_keys                   | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------------------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | customers | NULL       | const | PRIMARY,customers_idx_combine_1 | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+-----------+------------+-------+---------------------------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

各列的含义如下:

  • id: SELECT 查询的标识符. 每个 SELECT 都会自动分配一个唯一的标识符
  • select_type: SELECT 查询的类型
  • table: 查询的是哪个表
  • partitions: 匹配的分区
  • type: join 类型
  • possible_keys: 此次查询中可能选用的索引
  • key: 此次查询中确切使用到的索引
  • ken_len: 表示查询优化器使用了索引的字节数
  • ref: 哪个字段或常数与 key 一起被使用
  • rows: 显示此查询一共扫描了多少行. 这个是一个估计值.
  • filtered: 表示此查询条件所过滤的数据的百分比
  • extra: 额外的信息

接下来我们详细看一下每个字段的具体含义:

select_type

select_type 表示了查询的类型, 它的常用取值有:

  • SIMPLE:表示此查询不包含 UNION 查询或子查询
  • PRIMARY:表示此查询是最外层的查询
  • UNION:表示此查询是 UNION 的第二或随后的查询
  • DEPENDENT UNION:UNION 中的第二个或后面的查询语句, 取决于外面的查询
  • UNION RESULT:UNION 的结果
  • SUBQUERY:子查询中的第一个 SELECT
  • DEPENDENT SUBQUERY:子查询中的第一个 SELECT, 取决于外面的查询. 即子查询依赖于外层查询的结果
  • DERIVED:当子查询是from子句时,其select_type为DERIVED

最常见的查询类别应该是 SIMPLE 了, 比如当我们的查询没有子查询, 也没有 UNION 查询时, 那么通常就是 SIMPLE 类型, 例如:

1.SIMPLE 情况:

mysql> EXPLAIN SELECT * FROM customers WHERE customerName=‘Herkku Gifts‘ AND phone=‘+47 2267 3215‘ AND customerNumber=167;
+----+-------------+-----------+------------+-------+---------------------------------+---------+---------+-------+------+----------+-------+
| id | select_type | table     | partitions | type  | possible_keys                   | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------------------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | customers | NULL       | const | PRIMARY,customers_idx_combine_1 | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+-----------+------------+-------+---------------------------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

2.UNION情况

  当通过union来连接多个查询结果时,第二个之后的select其select_type为UNION

mysql> EXPLAIN SELECT customerNumber FROM customers WHERE customerNumber IN (125,144) UNION SELECT customerNumber FROM customers WHERE country IN (‘USA‘,‘France‘);
+----+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| id | select_type  | table      | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra                    |
+----+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
|  1 | PRIMARY      | customers  | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |    2 |   100.00 | Using where; Using index |
|  2 | UNION        | customers  | NULL       | ALL   | NULL          | NULL    | NULL    | NULL |  122 |    20.00 | Using where              |
| NULL | UNION RESULT | <union1,2> | NULL       | ALL   | NULL          | NULL    | NULL    | NULL | NULL |     NULL | Using temporary          |
+----+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
3 rows in set, 1 warning (0.00 sec)

3.DEPENDENT UNION与DEPENDENT SUBQUERY

  当union作为子查询时,其中第二个union的select_type就是DEPENDENT UNION。第一个子查询的select_type则是DEPENDENT SUBQUERY

mysql> EXPLAIN SELECT * FROM customers WHERE customerNumber IN (SELECT customerNumber FROM customers WHERE customerNumber IN (125,144) UNION SELECT customerNumber FROM customers WHERE country IN (‘USA‘,‘France‘));
+----+--------------------+------------+------------+--------+---------------+---------+---------+------+------+----------+--------------------------+
| id | select_type        | table      | partitions | type   | possible_keys | key     | key_len | ref  | rows | filtered | Extra                    |
+----+--------------------+------------+------------+--------+---------------+---------+---------+------+------+----------+--------------------------+
|  1 | PRIMARY            | customers  | NULL       | ALL    | NULL          | NULL    | NULL    | NULL |  122 |   100.00 | Using where              |
|  2 | DEPENDENT SUBQUERY | customers  | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | func |    1 |   100.00 | Using where; Using index |
|  3 | DEPENDENT UNION    | customers  | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | func |    1 |    20.00 | Using where              |
| NULL | UNION RESULT       | <union2,3> | NULL       | ALL    | NULL          | NULL    | NULL    | NULL | NULL |     NULL | Using temporary          |
+----+--------------------+------------+------------+--------+---------------+---------+---------+------+------+----------+--------------------------+
4 rows in set, 1 warning (0.00 sec)

4.SUBQUERY

  子查询中的第一个select其select_type为SUBQUERY

mysql> EXPLAIN SELECT * FROM customers WHERE customerNumber=(SELECT customerNumber FROM customers WHERE customerNumber=124);
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table     | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | PRIMARY     | customers | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL        |
|  2 | SUBQUERY    | customers | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | Using index |
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

mysql> EXPLAIN SELECT * FROM customers WHERE customerNumber in (SELECT customerNumber FROM customers WHERE customerNumber=124);
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table     | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | customers | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL        |
|  1 | SIMPLE      | customers | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | Using index |
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

思考下为什么一个用了in一个用了=反而select_type就不一样了????

5.DERIVED

mysql> EXPLAIN SELECT * FROM (SELECT COUNT(*) FROM customers WHERE customerNumber=124) a;
+----+-------------+------------+------------+--------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table      | partitions | type   | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+------------+------------+--------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | PRIMARY     | <derived2> | NULL       | system | NULL          | NULL    | NULL    | NULL  |    1 |   100.00 | NULL        |
|  2 | DERIVED     | customers  | NULL       | const  | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | Using index |
+----+-------------+------------+------------+--------+---------------+---------+---------+-------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

table

表示查询涉及的表或衍生表

partitions

匹配的分区

type

type 字段比较重要, 显示连接使用了何种类型。从最好到最差的连接类型依次分别为consteq_regrefrangeindexALL 它提供了判断查询是否高效的重要依据依据。

通过 type 字段, 我们判断此次查询是 全表扫描 还是 索引扫描 等。

type显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
  一般来说,得保证查询至少达到range级别,最好能达到ref。

type 常用的取值有:

  system: 表中只有一条数据. 这个类型是特殊的 const 类型

  const: 针对主键或唯一索引的等值查询扫描, 最多只返回一行数据. const 查询速度非常快, 因为它仅仅读取一次即可。

  例如下面的这个查询, 它使用了主键索引, 因此 type 就是 const 类型的

mysql> EXPLAIN SELECT * FROM customers WHERE customerName=‘Herkku Gifts‘ AND phone=‘+47 2267 3215‘ AND customerNumber=167;
+----+-------------+-----------+------------+-------+---------------------------------+---------+---------+-------+------+----------+-------+
| id | select_type | table     | partitions | type  | possible_keys                   | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------------------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | customers | NULL       | const | PRIMARY,customers_idx_combine_1 | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+-----------+------------+-------+---------------------------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

原文地址:https://www.cnblogs.com/MrFiona/p/10925919.html

时间: 2024-10-09 14:15:13

Mysql系列-性能优化神器EXPLAIN使用介绍及分析的相关文章

转:MySQL性能优化神器Explain使用分析

详细请点击 https://blog.csdn.net/qq_38293564/article/details/80883704 以下是自己总结: 接下来我们来重点看一下比较重要的几个字段 type type类型的性能比较 通常来说,不同的 type 类型的性能关系如下: ALL < index < range ~ index_merge < ref < eq_ref < const < system ALL 类型因为是全表扫描,因此在相同的查询条件下,它是速度最慢的.

MySQL 性能优化神器 Explain 使用分析

简介 MySQL 提供了一个 EXPLAIN 命令, 它可以对 SELECT 语句进行分析, 并输出 SELECT 执行的详细信息, 以供开发人员针对性优化.EXPLAIN 命令用法十分简单, 在 SELECT 语句前加上 Explain 就可以了, 例如: EXPLAIN SELECT * from user_info WHERE id < 300; 准备 为了接下来方便演示 EXPLAIN 的使用, 首先我们需要建立两个测试用的表, 并添加相应的数据: CREATE TABLE `user_

架构设计:系统存储(9)——MySQL数据库性能优化(5)

=================================== (接上文<架构设计:系统存储(9)--MySQL数据库性能优化(5)>) 4-3-3-3.避免死锁的建议 上一篇文章我们主要介绍了MySQL数据库中锁的基本原理.工作过程和产生死锁的原因.通过上一篇文章的介绍,可以确定我们需要业务系统中尽可能避免死锁的出现.这里为各位读者介绍一些在InnoDB引擎使用过程中减少死锁的建议. 正确使用读操作语句 经过之前文章介绍,我们知道一般的快照读是不会给数据表任何锁的.那么这些快照读操作

MySQL数据库性能优化的技巧和窍门

数据库表表面上存在索引和防错机制,然而一个简单的查询就会耗费很长时间.Web应用程序或许在开发环境中运行良好,但在产品环境中表现同样糟糕.如果你是个数据库管理员,你很有可能已经在某个阶段遇到上述情况.因此,本文将介绍对MySQL进行性能优化的技巧和窍门. 1.存储引擎的选择 如果数据表需要事务处理,应该考虑使用InnoDB,因为它完全符合ACID特性.如果不需要事务处理,使用默认存储引擎MyISAM是比较明智的.并且不要尝试同时使用这两个存储引擎.思考一下:在一个事务处理中,一些数据表使用Inn

170727、MySQL查询性能优化

MySQL查询性能优化 MySQL查询性能的优化涉及多个方面,其中包括库表结构.建立合理的索引.设计合理的查询.库表结构包括如何设计表之间的关联.表字段的数据类型等.这需要依据具体的场景进行设计.如下我们从数据库的索引和查询语句的设计两个角度介绍如何提高MySQL查询性能. 数据库索引 索引是存储引擎中用于快速找到记录的一种数据结构.索引有多种分类方式,按照存储方式可以分为:聚簇索引和非聚簇索引:按照数据的唯一性可以分为:唯一索引和非唯一索引:按照列个数可以分为:单列索引和多列索引等.索引也有多

mysql数据库性能优化(包括SQL,表结构,索引,缓存)

优化目标减少 IO 次数IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作所占用的,减少 IO 次数是 SQL 优化中需要第一优先考虑,当然,也是收效最明显的优化手段.降低 CPU 计算除了 IO 瓶颈之外,SQL优化中需要考虑的就是 CPU 运算量的优化了.order by, group by,distinct … 都是消耗 CPU 的大户(这些操作基本上都是 CPU 处理内存中的数据比较运算).当我们的 IO 优化做到一定阶段之后

Mysql数据库性能优化(一)

参考 http://www.jb51.net/article/82254.htm 今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我们程序员需要去关注的事情.当我们去设计数据库表结构,对操作数据库时(尤其是查表时的SQL语句),我们都需要注意数据操作的性能.这里,我们不会讲过多的SQL语句的优化,而只是针对MySQL这一Web应用最多的数据库. mysql的性能优化无法一蹴而就,必须一步一步慢慢来,从各个方面

架构设计:系统存储(8)——MySQL数据库性能优化(4)

================================ (接上文<架构设计:系统存储(7)--MySQL数据库性能优化(3)>) 4-3.InnoDB中的锁 虽然锁机制是InnoDB引擎中为了保证事务性而自然存在的,在索引.表结构.配置参数一定的前提下,InnoDB引擎加锁过程是一样的,所以理论上来说也就不存在"锁机制能够提升性能"这样的说法.但如果技术人员不理解InnoDB中的锁机制或者混乱.错误的索引定义和同样混乱的SQL写操作语句共同作用,那么导致死锁出现的

mysql innodb 性能优化

默认情况下,innodb的参数设置的非常小,在生产环境中远远不够用比如最重要的两个参数innodb_buffer_pool_size 默认是8Minnodb_flush_logs_at_trx_commit 默认设置的是1 也就是同步刷新log(可以这么理解) innodb_buffer_pool_size: 这是InnoDB最重要的设置,对InnoDB性能有决定性的影响.默认的设置只有8M,所以默认的数据库设置下面InnoDB性能很差.在只有 InnoDB存储引擎的数据库服务器上面,可以设置6