MYSQL调优——添加索引

MYSQL调优

1.SQL优化准备

sql性能问题
a.分析SQL的执行计划 : explain ,可以模拟sql优化器执行sql语句,从而让开发人员知道自己编写的sql
b.MYSQL查询优化器会干扰我们的优化

优化方法:官网:官网地址
查询执行计划: explain + SQL语句 例:explain select * from payment
查询出来的例子
各个字段代表的含义:

id: 编号
select_type: 查询类型
table:表
type: 类型
possible_type: 预测用到的索引
key: 实际使用的索引
ley_len: 实际使用索引的长度
ref:表之间的引用关系
rows: 通过索引查询到的数据量
Extra: 额外的信息

1.创建三张表

在这里插入图片描述
查询课程编号为2 或教师证编号为3 的老师信息 explain+sql

EXPLAIN select t.* from teacher t,course c,teacherCard tc where t.tid=c.tid and t.tcid =tc.tcid and (c.cid = 2 or tc.tcid=3)

查询结果:

在这里插入图片描述

各个字段代表的含义

id

id值相同 (从上往下 顺序执行 (t-tc-c))

表的执行顺序 因数量的个数改变而改变的原因:笛卡尔积

a b c 笛卡尔积
3 4 4 3x4=12x4=48(正常的顺序)
4 4 3 4x4=16x3=48(非正常顺序)

虽然结果都是48相同,但是第一次笛卡尔积数量较少,所以正确的顺序为
3-4-4.
所以 数据小的表 优先查询(小表驱动大表)

id值不同

id值越大越优先查询
本质:在嵌套子查询时,先查内层,再查外层
例:查询教授SQL课程的老师的描述(desc字段)
explain select tc.tcdesc from teacherCard tc,course c,teacher t where t.tid=c.tid and t.tcid =tc.tcid and c.cname=‘sql’
将以上多表查询转化为子查询模式
explain select tc.tcdesc from teachercard where tc.tcid=(select t.tcid from teacher t where t.tid=(select c.tid from course c where c.cname=‘sql’))
结果:
在这里插入图片描述
根据上图结果可以知道查询顺序 c-t-tc

子查询+多表:
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 c.cname=‘sql’)
结果:
在这里插入图片描述
id值有相同又有不同,id值越大越优先;id值相同,从上往下,顺序执行

select_type

PRIMARY: 包含子查询SQL中的主查询(最外层)
SUBQUERY: 包含子查询SQL中的子查询(非最外层)
simple:简单查询(不包含子查询,union) 例:select * from teacher
derived:衍生查询(使用到了临时表)
          a:在from子查询中只有一张表
                select cname  from  (select * from course where tid in(1,2)) cr (5.5版本 高一级的版本可能为simple查询)
          b: 在from子查询中,如果有table1 union table2 ,则table1 就是derived  table2 是union
          EXPLAIN SELECT cr.cname  FROM  (SELECT * FROM course WHERE tid = 1 UNION SELECT * FROM course WHERE tid=2) cr
          结果如下:
          ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200824170320603.png#pic_center)
union:上例中的b
union result:告知开发人员哪些表存在uniton查询

TYPE 索引类型、类型

用的较多:system>const>eq_ref>ref>range>index>all (按照性能排序)
其中system和const只是理想情况,一般达不到 。实际能达到一般为ref和range,不进行优化为all (对type进行优化的前提是有索引)

system(忽略)

只有一条数据的系统表 或 衍生表只有一条数据的主查询

const

仅仅能查询到一条数据的sql语句 ,用于primary key 或unique索引

eq_ref

唯一性索引,对于每个索引键的查询,返回匹配的为一行数据(有且只有一个,不能多,不能为0)常见于唯一索引和主键索引

select ... from .. where name= ... (name添加了索引且name唯一) 

例子:
给teachercard表添加主键
ALTER TABLE teachercard ADD CONSTRAINT pk_tcid PRIMARY KEY(tcid)
给teacher表的tcid字段添加唯一
ALTER TABLE teachercard ADD CONSTRAINT uk_tcid UNIQUE INDEX(tcid)
查询

select t.tcid from teacher t, teachercard tc where t.tcid=tc.tcid

在这里插入图片描述
以上sql,用到的索引 t.tcid 即 teacher表中的tcid字段,如果teacher表的数据个数和链接查询的数据个数一致,则有可能数显eq_ref级别。

ref

非唯一索引,对于每个索引键的查询,返回匹配的所有行(0,多)
teacher表数据
在这里插入图片描述
teachercard表数据
在这里插入图片描述
目前tname=‘tz’的数据有两个

给tname添加索引:

ALTER TABLE teacher ADD INDEX index_tname(tname)

查询

explain select * from teacher where tname='tz'

range

检索指定范围的行,where后面是一个范围查询(between,in,>,<等,其中in可能会失效,从而变成无索引 all)

创建索引

 alter table teacher add index index_tid(tid)

查询

explain select t.* from teacher t where t.tid < 3 

index

查询所有的索引的数据

explain select t.tid from teacher t #其中tid字段添加了索引

all

查询全部表中的数据

explain select cid from course # cid没有任何索引

总结

system/const: 结果只有一条数据
eq_ref: 结果多条,但是每条数据唯一
ref:结果多条,但是每条数据是0或多条


possible_keys

可能用到的索引,是一种预测,不准。
如果possible_keys 为null,则说明没用索引

key

实际使用到的索引
如果possible_keys 为null,则说明没用索引

key_len

索引的长度,用于判断复合索引是否完全被使用。在utf8中一个字符占3个字节
1.如果这个字段为char(3),则key_len=9,如果这个字段可以为空,则key_len=10,会使用一个字节用于标识
2.如果这个字段为varchar(20) 则key_len=63
原因为 20*3(utf8)+ 1(null) + 2(可变长度)

总结

utf8: 1个字符3个字节
gbk: 1个字符2个字节
latin: 1个字符1个字节
可以为null: 加1
可变字节 : 加2

ref (注意和type中的ref区分)

作用:指明当前表参照的字段
例:

select ... from ... where a.c=b.x # 其中b.x可以为常量,const ,其中a.c和b.x必须有索引

rows

被索引优化查询的数据个数 (实际通过索引查询到的数据个数)

Extra

using filesort (性能消耗大:需要一次“额外”的排序(查询),常见于order by)
  排序前提:要先查找
例:单索引
select ... from text where a1='' order by a2 

由于先执行前面语句不执行排序,然后导致a2要进行一次额外的查询.所以对于单索引,如果排序和查找是同一个字段,不会出现using filesort 如果不是同一个字段则会出现using filesort。使用where后面的条件可以避免

复合索引:不能跨列(最佳左前缀)
例:

alter table test add index index_all(a1,a2,a3) # 添加索引
explain select * from test where a1='' order by a3

上面这条sql语句跨越了a2所以也会出现using filesort。通过 where和order by 按照复合索引的顺序使用,不要跨列或无序使用

using temporary(性能损耗大,用到了临时表,常见于group by)

避免:查询哪些列就通过哪些列进行分组,由于额外多出了一张表(5.5版本)

from…on … join … where … group by having…select dinstinct …order by limit

using index(性能提升;索引覆盖。原因:不读取原文件,只从索引文件中读取数据(不需要回表查询))

只要使用到的列全部都在索引中,就是索引覆盖 using index
例:

select age from ... where age=..  # 其中age是索引字段

具体:test表中有一个复合索引(a1,a2,a3)

select a1,a2 from test where a1='' and a2=''

总结:
如果用到了索引覆盖using index时,会对possible_keys和key造成影响
a.如果没有where,则索引出现在key中
b.如果有where,则索引出现在key和possible_keys中

using where(需要回表查询)
select name,age from test where age=21 #其中age是索引列,但是name不是
impossible where (where子句永远为false)

例:

select * from test where age=11 and age=12

2.SQL优化开始

单表

1 创建一张表

create table test03
(
 a1 int(4) not null,
 a2 int(4) not null,
 a3 int(4) not null,
 a4 int(4) not null
);
alter table test03 add index idx_all(a1,a2,a3,a4)

2.SQL语句
理想情况

explain select a1,a2,a3,a4 from test03 where a1=1 and a2=2 and a3=3 and a4=4

如果数据顺序和索引顺序不一致,sql优化器会自动帮忙优化
SQL列缺省

select a1,a2,a3,a4 from test03 where a1=1 and a2=2 and a4=4 order by a3

这时候extra会出现using index 和 using where ,由于符合索引跨列了

select a1,a2,a3,a4 from test03 where a1=1 and a4=4 order by a3

上面这条sql出现了using index ,using where using filesort。本质原因:跨列使用(顺序应为a1,a2,a3,a4,上上条sql中where和order by 顺序为 a1,a2,a3,而上条sql中where 和order by为 a1,a3跨列了,所以出现using filesort。如果上条sql语句改为order by a2,a3则不会出现using filesort)

总结:
1.如果a,b,c,d复合索引和使用的顺序全部一致(且不跨列使用),则复合索引全部使用。如果部分一致(且不跨列使用),则使用部分索引
2.where和order by不要跨列使用

多张表

创建两张表

create table teacher2
(
tid int(4) primary key,
cid int(4) not null
);
insert into teacher2 values(1,2);
insert into teacher2 values(2,1);
insert into teacher2 values(3,3);
create table course2
(
cid int(4),
cname varchar(20)
);
insert into course2 values(1,'java');
insert into course2 values(2,'python');
insert into course2 values(3,'web');

左连接

select * from teacher2 t left join course2 c on t.cid=c.cid where c.cname-'java'

优化:
1.小表驱动大表,小表放在等号左边 例如:t(小).id=c(大).id)
2.索引简历经常使用的字段上,例如t.id=c.id,由于t.id用到比较多,所以应该在t.id添加索引

给上面左连接添加索引

alter table teacher2 add index index_teacher2_cid(cid)

避免索引失效原则

1.符合索引,不要跨列或者无序使用(最佳左前缀)
2.复合索引,尽量使用全索引匹配
3.不要在索引上进行任何操作(计算,函数,类型转换),否则索引失效,如果复合索引左边失效则右边也失效
4.索引不能使用(!= , <>或is null),否则自身和右边索引全部失效。

SQL优化是一种概率层面的优化。至于是否实际使用了优化,需要通过explain进行推测。
补救:尽量使用覆盖索引(using index)
例:(a,b,c)

select a,b,c from test where a=.. and b=..

猜你喜欢

转载自blog.csdn.net/qq_41576091/article/details/108195215