MySQL优化基础

导读:

       当一个sql查询语句被写出来之后,其实你的工作只完成了一小半,接下来更重要的工作是评估你自己写的sql的质量与效率。mysql为我们提供了很有用的辅助武器explain,它向我们展示了mysql接收到一条sql语句的执行计划。根据explain返回的结果我们便可以知道我们的sql写的怎么样,是否会造成查询瓶颈,同时根据结果不断的修改调整查询语句,从而完成sql优化的过程。

      虽然 explain返回的结果项很多,这里我们只关注如下几点:

准备三张表:

图1

1)ID值:

1.1、ID值相同,从上至下依次顺序执行,且表的数据量越小越被先执;

mysql> explain select t.* from teacher t,course c,teacherCard tc

    -> where t.tid=c.tid and t.tcid=tc.tcid and (c.cid=3 or tc.tcid=3);

图2

1.2、ID值不同,越大越先执行(先执行最内层子查询,再查子查询,再查主查询);

mysql> explain select tc.tcdesc from teacherCard tc where tcid=(

    -> select t.tcid from teacher t where t.tid=(

    -> select c.tid from course c where c.cname='sql'));

图3

1.3、ID相同又不同,先执行ID大的,后依次顺序执行ID相同的;

mysql> explain select t.tname,tc.tcdesc from teacher t,teacherCard tc

    -> where t.tcid=tc.tcid and t.tid=(

    -> select c.tid from course c where cname='sql');

图4

2)select type

PRIMARY:SQL中包含子查询种的主查询(最外层查询);

SUBQUERY:被包含在主查询(外层查询)中的查询(非最外层查询);

simple:检查查询(不含子查询、union);

derived:衍生查询(查询中用到了临时表);

a.在from子查询中只有一张表

explain select cr.cname from (select * from course where tid in (1,2))cr;

图5

b.在from子查询中,如果有table1 union table2,则table1就是derived,table2是union表

explain select cr.cname from (select * from course c1 where tid=1 union  select * from course c2 where tid=2) cr;

图6

union result:告知开发人员,那几行表之间进行了union操作。

3)type:索引类型

常见的type类型:system>const>eq_ref>ref>range>index>all,type优化前提是有索引。

其中:实际能达到的只有ref和range级别。

3.1、const:仅仅能查到一条数据的SQL,且用于Primary key或unique索引(主要与索引类型有关);

准备一张只有一条数据的表test01

图7

为test01表添加unique索引

图8

mysql> explain select tid from test01 where tid=1;

图9

将unique index变为普通index后结果如下:

图10

3.2、eq_ref:唯一索引,对于每个索引键的查询,返回匹配唯一一行数据(有且只有一行,不能为0行或多行);

mysql> select t.tcid from teacher t,teacherCard tc where t.tcid=tc.tcid;

图12

mysql> explain select t.tcid from teacher t,teacherCard tc where t.tcid=tc.tcid;

图12

以上SQL,用到的索引是t.tcid,即teacher表中的tcid字段;如果teacher表的数据个数和连接查询的数据个数一致,则有可能达到eq_ref级别。

3.3、ref:非唯一性索引,对于每个索引键的查询,返回匹配的所有行数据(0或多行)。

先看teacher表数据

图13

给teache在tname字段上加索引

图14

mysql> explain select * from teacher where tname='tz';

mysql> explain select tname from teacher where tname='tz';

图15

3.4、range:检索指定范围的行,where后面是一个范围查询(between,in,> ,<,>=)

图16

3.5、index:查询全部索引数据

explain select tname from teacher;

图17

3.6、all:查询所有数据

图18

小结:

system/const:结果只有一条数据;

eq_ref:结果多条 ,但是每条数据是唯一的;

ref:结果多条,但是每条数据是0或多条。

4)possible_keys:可能用到的索引,是一种预测,不一定是实际用到

5)key:实际用到的索引,NUll表示没用到索引

6)key_len:索引的长度

作用:用于判断复合索引是否被完全使用。

准备一张表test_k1表

图19

为name添加索引

图20
图21

给name1也增加索引

图22
图23

说明:utf8中,如果字段值为空,则mysql用1个字节标识控制,key_len=20*3+1=61

删除之前的索引,创建复合索引

图24

mysql> explain select * from test_k1 where name1='';

图25

为name2列加索引,name2类型为varchar(20)

mysql> alter table test_k1 add index idx_name2(name2);

图26
图27

说明:在utf8中,mysql用两个字节标识可变长度varchar,1个字节标识null,key_len=20*3+1=2=63。

7)rows:被索引优化查询的数据个数

8)Extra:

8.1、using filesort:性能消耗大,需额外的意思排序(查询),常见于order by中。

准备表:

图29

8.1.1、单列索引:给a1列添加单列索引

mysql> alter table test02 add index idx_a1(a1);

图30

mysql> explain select a1 from test02 order by a1;

图31

小结:对于单索引如果排序和查找是同一个字段,则不会出现using filesort。

8.1.2、复合索引:不能跨列,最佳左前缀

创建复合索引:

mysql> alter table test02 add index a1_a2_a3(a1,a2,a3);

图32

mysql> explain select * from test02 where a1='' order by a3;

图33
图34
图35

小结:where和order by按照复合索引的顺序使用,不要跨列使用。

8.2、using temporary:性能损耗大,用到了临时表,常见于group by中。

mysql> explain select a1,a2 from test02 where a1=1 and a2=2 group by a3;

图36

mysql> explain select a1,a2 from test02 where a1=1 and a2=2 group by a2;

图37

mysql> explain select a1,a2 from test02 where a1=1 and a2=2 group by a1;

图38

mysql> explain select a1,a2 from test02 where a1=1 and a2=2 group by a1,a2;

图39

mysql> explain select a1,a2 from test02 where a1=1 and a2=2 group by a2,a1;

图40

mysql> explain select a1,a2 from test02 where a2=2 and a1=1 group by a2,a1;

图41

小结:查询顺序、筛选顺序和分组顺序一定要一直才不会出现using temporary。

8.3、using index:性能提升,索引覆盖

原因:只从索引中读取数据,不需要回表查询。只要使用到的列全部包含在索引里,那么就是using index索引覆盖。

图42

mysql> explain select a1,a2,a3 from test02;

图43

小结:

using index时,会对possible_keys和key造成影响

a.如果没有where,则索引只出现在key中;

b.如果有where,则索引出现在key和possibles_key中。

8.4、using where:必须要回表查。

删除基于a1、a2、a3的复合索引,创建基于a1,a2的复合索引

图44
图45

8.5、immpossible where:where子句永远为false。

mysql> explain select * from test02 where a1='x' and a1='y';

图46
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容