ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

小白都能秒懂的EXPLAIN关键字,对300w测试数据进行优化

2021-04-13 13:33:04  阅读:225  来源: 互联网

标签:title EXPLAIN 测试数据 查询 索引 300w test where select


下面都是以MYSQL8.0版本测试。

关闭MYSQL缓存.

目录

下面都是以MYSQL8.0版本测试。

关闭MYSQL缓存.

MYSQL架构图

Explain关键字使用

Explain 下各个字段作用

解释一下覆盖索引及回表查询

上面讲了Explain关键字所有字段意思和基础运用,现在来分析哪种情况导致索引失效。

以上就是本次优化知识,比如group by 的优化呀 ,order by的优化,目前一张表数据不太容易做,下次更新。


MYSQL架构图

第一层是一种通用架构,大多数基于客户端/服务器的应用软件都有,主要是建立连接,授权处理,安全认证。

第二层是核心架构,包括缓存、查询解析,优化,核心函数(日期,数学函数,加密函数),以及所有跨存储引擎的功能都在这里实现:存储过程,触发器,视图等等。

第三层是存储引擎层,存储引擎负责MYSQL中数据的存储和提取。和GUN/LINUX下的各种文件系统一样,每个存储引擎都有它的优势和劣势。服务器通过API与存储引擎进行通信。

存储引擎API包含了几十个底层函数,用于执行诸如“开始一个事务” 或者 “根据主键提取一行记录”等操作,但是存储引擎并不会去解析SQL(INNODB会解析外键,因为只有INNODB才支持外键)

不同存储引擎之前也不会相互通信,而只是简单地响应上层服务器的请求。

Explain关键字使用

直接通过在查询语句前加上explain ,如 explain select * from test ;

Explain 下各个字段作用

id:从id属性可以得知表的执行顺序

举个例子:

查询1  explain select * from test ;  

查询2  explain select * from score sc where sc.s_id in (select stu.s_id from student stu);

查询3  explain select * from `test` union select * from `test`;

结果集如图:

所以这个有三种情况:

  1. id相同,则从上至下执行
  2. id不同,则id越大优先级越高,执行最早
  3. id既有相同也有不同的,则相同会认为是一组,从上往下执行,然后根据每组id,id越大优先级越高,越先执行。

select_type:查询的类型

比如上图,有simple-简单查询,有primary-复杂查询。

一共有5种

  1. Simple:简单的select查询,查询中不包含子查询或者union,即就一个简单的select * from 表名  ,那么就是simple
  2. Primary:复杂查询最外面一个查询,比如上面查询三中第一个select * from test 就是primary 。
  3. subquery:在select或者where列表中包含子查询
  4. derived:在from列表中包含的子查询被标记为DERIVED(衍生表),mysql会递归这些子查询,放在临时表中。
  5. union:若有union查询,则union后面的表则是union,若union包含在from子句的子查询中,外层select将被标记为:DERIVED;

table:查询的表名

partitions:表所在分区,若操作了分库分表这里就会显示

type:访问类型。显示查询使用了何种类型,从最好到最差依次是:system > const > eq_ref > ref > range > index > all

 

  1. system:表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,这个也可忽略不计;
  2. const:表示通过索引一次就找到了,const用于比较primary key或者unique索引。因为只匹配一行记录,所以很快. 如果将主键置于where列表中,mysql就能将该查询转换成一个常量;
  3. eq_ref:唯一性索引扫描,对于每一个索引键,表中只有一条记录与之匹配,常用于主键或唯一索引扫描;
  4. ref:非唯一性索引扫描,返回匹配某个单独值得所有行,本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以它应该属于查找和扫描的混合体;
  5. range:只检索给定范围的行,使用一个索引来选择行,key列显示使用哪个索引,一般就是在你的where语句中出现了between,<,>,in等的查询;这种范围索引扫描比全表扫描要好,因为它只需要开始于索引的某一个点,结束于另一个点,不用扫描全部索引;
  6. index:index于all区别为index类型只遍历索引树,这通常比all快,因为索引文件通常比数据文件小;也就是说虽然all和index都是读写表,但index是从索引中读取的,而all是从硬盘中读的;
  7. all:也就是全表扫描;

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

举例: 以我这个300w test表 数据为准  , 只有主键有索引

  1. 直接根据主键查询。(很明显type=const)



    所以,结论就是根据主键查询效率是非常高的。
  2. title列设置为普通索引,根据索引查询。 可以看到非唯一性索引查询是ref


     
  3. title列设置为全文索引,根据全文索引查询。(可以看到走的是ALL,并且全文索引失效了),提一个思考题为什么全文索引失效了?

  4. title列不设置索引,直接查询。 (可以发现与设置了全文索引相同,说明上面的全文索引肯定失效了)

 

possible_keys:显示可能会被应用到这张表的索引,一个或者多个;查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用到;

key:实际使用到的索引.如果为null,则没有使用索引;查询中若使用了覆盖索引,则该索引仅出现在key列表中;

key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度,在不损失精确性的情况下,长度越短越好; key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的;

ref:显示索引的哪一列被使用了,如果可能的话,是一个常数,哪些列或常量被用于查找索引列上的值;

rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数;

Extra:包含不适合在其它列中显示但十分重要的额外信息

  1. using filesort(出现这个东西不好):说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取,mysql中无法利用索引完成的排序操作称为"文件排序";

  2. using temporary(出现这个东西更不好,使用到了临时表):使用了临时表保存中间结果,Mysql在对查询结果排序时使用临时表,常见于排序order by和分组查询group by。

  3. using index:表示相应的select操作中使用了覆盖索引(Covering Index),避免了访问了表的数据行,效率不错!如果同时出现using where ,表明索引被用来执行索引键值的查找;

    如果没有同时出现using where,表明索引用来读取数据而非执行查找操作。

解释一下覆盖索引及回表查询

在INNODB引擎中,由于聚簇索引直接保存了行数,叶子节点所在的二级索引则保存了指向一级索引即聚簇索引的指针,若没有设置覆盖索引,则查找了索引后还需要二次查询索引并返回数据。

通过二次查询索引导致二次定位数据行称回表查询。换句话说就是查的字段有没有用到索引

上面讲了Explain关键字所有字段意思和基础运用,现在来分析哪种情况导致索引失效。

  1. 使用like关键字 , '%零%' ; sql:explain SELECT options_start FROM test where title like '%零%';



    很明显,尽快title加了索引,但是一旦用了like查询,索引失效!

    第二种情况,explain SELECT options_start FROM test where title like '零%';



    发现走了tilte索引,所以若一定要使用like 关键字,尽可能确认前缀再去匹配 。

    第三种情况,explain SELECT options_start FROM test where title like '%零';



    很明显也没走索引,和第一种一个结果。

    结论:目前没有想到什么原因导致这种情况,我想着应该是给了前缀后,mysql优化器会将词缀分开并解析。
  2. 使用 in 关键字  , explain SELECT options_start FROM test where title in ('霏丝佳;PHYSI0GEL','0四七九','降米唐0号');



    走了title索引 。

    第二种组合,in 中使用子查询 explain SELECT options_start FROM test where title in (select title from test where id > 60 );




    很明显,in中套子查询外层查询也不走索引。


    结论:很容易发现in后面接任何的查询都不会走索引,not in 很显然也是一样的效果 。

    在翻阅资料时发现一个解释, in 中的子查询要放一个小表进去,应该要小表驱动大表进行查询,即外层查询表(数据量小-》小表),子查询(数据量远远大于外层循环-》称为大表)-》 这个原因解释为,我认为是不对的。

    SELECT options_start FROM test where title in (select title from test where id > 60 );
    SELECT options_start FROM test t1 where exists (select 1 from test t2 where t2.id > 60 and t1.title=t2.title);  这是测试的exists 
    大表驱动小表  测试300w数据 , in 查询时间17.098s , exists 查询时间17.269s。

    select t1.options_start from test t1 where t1.id > 60 and t1.title in (select title from test);
    select t1.options_start from test t1 where t1.id > 60 and exists (select 1 from test where title=t1.title);
    小表驱动大表 测试300w数据 , in 查询时间22.674s , exists 查询时间是19.231s 

    两个测试得出结论,现在很多博客上面写的测试是有问题的,in 接子查询 应该要是大表驱动小表更快 ,而exists 接子查询 则是小表驱动大表更快。  -》用到不可避免用到子查询时用exists 代替 in 。

 

以上就是本次优化知识,比如group by 的优化呀 ,order by的优化,目前一张表数据不太容易做,下次更新。

 

 

 

 

 

 

 

 

 

标签:title,EXPLAIN,测试数据,查询,索引,300w,test,where,select
来源: https://blog.csdn.net/asd991543753/article/details/115561816

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有