MySql执行计划Explain的原理与应用

MySql执行计划Explain的原理与应用

**

一、目标

**

1、知道怎么用Explain;

2、学会使用Explain优化sql语句,获得最优查询效率;

二、Explain介绍

在select语句之前增加explain关键字,执行后MySQL就会返回执行计划的信息,而不是执行sql。但如果from中包含子查询,MySQL仍会执行该子查询,并把子查询的结果放入临时表中。

三、Explain的12列

1、id列

id列的编号是select的序列号,有几个select就有几个id,并且id是按照select出现的顺序增长的,id列的值越大优先级越高,id相同则是按照执行计划列从上往下执行,id为空则是最后执行。

2、select_type列

表示对应行是简单查询还是复杂查询。

(1)simple:不包含子查询和union的简单查询

(2)primary:复杂查询中最外层的select

(3)subquery:包含在select中的子查询(不在from的字句中)

(4)derived:包含在from字句中的子查询。mysql会将查询结果放入一个临时表中,此临时表也叫衍生表。

注意:当在 MySQL 中执行查询时出现 Derived 时,这意味着查询中包含子查询。这些子查询可以是内联、外联或标量子查询。如果这些子查询不是很好优化,可能会导致查询性能下降。

以下是一些优化 SQL 的方法:

1.尽可能使用 JOIN 而不是子查询。JOIN 可以更好地优化,因为它可以使用索引来加速查询。

2.使用 EXISTS 或 NOT EXISTS 而不是 IN 或 NOT IN。EXISTS 可以更好地优化,因为它只需要找到一个匹配项就可以停止查询。

3.避免在 SELECT 子句中使用子查询。如果必须使用子查询,请尽可能将其移动到 FROM 子句中。

4.尽可能使用 UNION ALL 而不是 UNION。UNION ALL 可以更好地优化,因为它不需要去重。

5.确保所有的列都被索引。如果没有索引,MySQL 将使用全表扫描,这会导致查询变慢。

6.避免在 WHERE 子句中使用函数或表达式。这会阻止 MySQL 使用索引来加速查询。
(5)union:在union中的第二个和随后的select,UNION RESULT为合并的结果

注意:当在 MySQL 中执行查询时出现 UNION 时,这意味着查询中包含多个 SELECT 语句。如果这些语句不能很好地优化,可能会导致查询性能下降。

以下是一些优化 SQL 的方法:

1.尽可能使用 UNION ALL 而不是 UNION。UNION ALL 不会进行重复项的去重,因此可以更快地执行查询。

2.使用 LIMIT 子句来限制结果集的大小。这可以减少查询的执行时间和内存使用。

3.将 UNION 查询的结果存储在临时表中,然后对临时表进行排序和过滤。这可以减少每个 SELECT 语句的执行时间,并且可以更好地利用索引。

4.在每个 SELECT 语句中使用 WHERE 子句来过滤结果集。这可以减少每个 SELECT 语句的执行时间,并且可以更好地利用索引。

5.将 UNION 查询转换为 JOIN 查询。JOIN 可以更好地优化,因为它可以使用索引来加速查询。

3、table列

表示当前行访问的是哪张表。当from中有子查询时,table列的格式为,表示当前查询依赖id=N行的查询,所以先执行id=N行的查询,如下面select_type列所示。当有union查询时,UNION RESULT的table列的值为<union1,2>,1和2表示参与union的行id。

4、partitions列

查询将匹配记录的分区。 对于非分区表,该值为 NULL。
5、type列

此列表示关联类型或访问类型。也就是MySQL决定如何查找表中的行。依次从最优到最差分别为:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > all。

常见的有:system > const > eq_ref > ref > range > index > all。

一般来说,得保证查询至少达到range级别,最好能达到ref。

(1)NULL:MySQL能在优化阶段分解查询语句,在执行阶段不用再去访问表或者索引。

(2)system、const:MySQL对查询的某部分进行优化并把其转化成一个常量(可以通过show warnings命令查看结果)。system是const的一个特例,表示表里只有一条元组匹配时为system,平时不会出现,这个可以忽略不计。const是查找条件是主键或者唯一,并且只匹配一行数据,意味着不用往下扫描了。

(3)eq_ref:主键或唯一键索引被连接使用,最多只会返回一条符合条件的记录。简单的select查询不会出现这种type。

(4)ref:相比eq_ref,不使用唯一索引,而是使用普通索引或者唯一索引的部分前缀,索引和某个值比较,会找到多个符合条件的行。

(5)range:通常出现在范围查询中,比如in、between、大于、小于等。使用索引来检索给定范围的行。

(6)index:这种连接类型只是另外一种形式的全表扫描,只不过它的扫描是按照索引的顺序,all是沿着磁盘扫描,index是沿着索引扫描。

(7) ALL:全表扫描,将遍历全表以找到匹配的行。

注意:当在 MySQL 中执行查询时,如果 EXPLAIN 中的 type 列显示为 ALL,则表示查询正在执行全表扫描。这意味着 MySQL 将扫描整个表来查找匹配的行,这可能会导致查询性能下降,特别是对于大型表。

以下是一些优化 SQL 的方法:

1.使用索引来加速查询。索引可以减少全表扫描的需要,从而提高查询性能。可以使用 EXPLAIN 来查看是否使用了索引。

2.使用 LIMIT 子句来限制结果集的大小。这可以减少查询的执行时间和内存使用。

3.只选择需要的列。如果查询只需要某些列,可以只选择这些列,而不是选择整个表。这可以减少查询的执行时间和内存使用。

4.避免在 WHERE 子句中使用函数或表达式。这会使 MySQL 无法使用索引,并且可能会导致全表扫描。

5.将 WHERE 子句中的常量放在等式左侧。这可以帮助 MySQL 使用索引,从而避免全表扫描。
6、possible_keys列

此列显示在查询中可能用到的索引。如果该列为NULL,则表示没有相关索引,可以通过检查where子句看是否可以添加一个适当的索引来提高性能。

7、key列

此列显示MySQL在查询时实际用到的索引。在执行计划中可能出现possible_keys列有值,而key列为null,这种情况可能是表中数据不多,MySQL认为索引对当前查询帮助不大而选择了全表查询。如果想强制MySQL使用或忽视possible_keys列中的索引,在查询时可使用force index、ignore index。
8、key_len列

此列显示MySQL在索引里使用的字节数,通过此列可以算出具体使用了索引中的那些列。索引最大长度为768字节,当长度过大时,MySQL会做一个类似最左前缀处理,将前半部分字符提取出做索引。当字段可以为null时,还需要1个字节去记录。

复制代码
    key_len计算规则:
      字符串:
          char(n):n个数字或者字母占n个字节,汉字占3n个字节
          varchar(n):  n个数字或者字母占n个字节,汉字占3n+2个字节。+2字节用来存储字符串长度。

      数字类型:
          tinyint:1字节      smallint:2字节               int:4字节             bigint:8字节

      时间类型
          date:3字节        timestamp:4字节          datetime:8字节

9、ref列

此列显示key列记录的索引中,表查找值时使用到的列或常量。常见的有const、字段名
10、rows列

此列是MySQL在查询中估计要读取的行数。注意这里不是结果集的行数。
11、filtered列

筛选的列表示按表条件筛选的表行的估计百分比。最大值是100,这意味着没有对行进行过滤。从100开始递减的值表示过滤量在增加。Rows显示检查的估计行数,Rows × filtered显示与下表连接的行数。例如,如果rows为1000,filtered为50.00(50%),则要与下表连接的行数为1000 × 50% = 500。

关注执行计划结果中其他列的值并优化查询更重要。比如为了避免出现filesort(使用可以满足order by的索引),即使filtered的值比较低也没问题。再比如上面filtered=0.1%的场景,我们更应该关注的是添加一个索引提高查询性能,而不是看filtered的值。
12、Extra列

此列是一些额外信息。

常见的重要值如下:

1)Using index:使用覆盖索引(如果select后面查询的字段都可以从这个索引的树中获取,不需要通过辅助索引树找到主键,再通过主键去主键索引树里获取其它字段值,这种情况一般可以说是用到了覆盖索引)。

2)Using where:使用 where 语句来处理结果,并且查询的列未被索引覆盖。

3)Using index condition:查询的列不完全被索引覆盖,where条件中是一个查询的范围。

4)Using temporary:MySQL需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的。

5)Using filesort:将使用外部排序而不是索引排序,数据较小时从内存排序,否则需要在磁盘完成排序。

6)Select tables optimized away:使用某些聚合函数(比如 max、min)来访问存在索引的某个字段时。

四、案例

1、如何判断是否需要添加索引

优化前:无索引

优化后:添加必要索引

2、尽可能使用 UNION ALL 而不是 UNION

优化前:使用了UNION

优化后:使用UNION ALL

五、总结

1.尽可能使用 JOIN 而不是子查询。JOIN 可以更好地优化,因为它可以使用索引来加速查询。

  1. 使用 EXISTS 或 NOT EXISTS 而不是 IN 或 NOT IN。EXISTS 可以更好地优化,因为它只需要找到一个匹配项就可以停止查询。

3.避免在 SELECT 子句中使用子查询。如果必须使用子查询,请尽可能将其移动到 FROM 子句中。

4.尽可能使用 UNION ALL 而不是 UNION。UNION ALL 可以更好地优化,因为它不需要去重。

5.确保所有的列都被索引。如果没有索引,MySQL 将使用全表扫描,这会导致查询变慢。

6.避免在 WHERE 子句中使用函数或表达式。这会使 MySQL 无法使用索引,并且可能会导致全表扫描。

7.将 WHERE 子句中的常量放在等式左侧。这可以帮助 MySQL 使用索引,从而避免全表扫描。

8.使用 LIMIT 子句来限制结果集的大小。这可以减少查询的执行时间和内存使用。

9.使用索引来加速查询。索引可以减少全表扫描的需要,从而提高查询性能。可以使用 EXPLAIN 来查看是否使用了索引。

10.只选择需要的列。如果查询只需要某些列,可以只选择这些列,而不是选择整个表。这可以减少查询的执行时间和内存使用。

相关推荐
会飞的架狗师6 小时前
【MySQL体系】第8篇:MySQL集群架构技术详解
数据库·mysql·架构
星光一影7 小时前
供应链进销存源码uniapp全开源ERP多仓库管理系统pc+app手机端
mysql·elementui·uni-app·开源·php·phpstorm·1024程序员节
ximy13359 小时前
Mysql基础知识之SQL语句——库表管理操作
sql·mysql·oracle
2501_938782099 小时前
《Ubuntu 系统下 MySQL 安装前的环境检查与依赖准备指南》
hive·mysql·ubuntu·adb
Java 码农9 小时前
mysql8.4.6 LTS 主从架构搭建
mysql·adb·架构
Dolphin_Home11 小时前
MySQL逗号分隔字段-历史遗留原因兼容方案
数据库·mysql
码力引擎12 小时前
【零基础学MySQL】第二章:SQL类型
数据库·sql·mysql·oracle
敲代码的嘎仔12 小时前
JavaWeb零基础学习Day5——MySQL
java·数据库·学习·程序人生·mysql·adb·改行学it