优化实例
创建一个表格
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_a1_a2_a3_a4(a1,a2,a3,a4);
写语句
explain select a1,a2,a3,a4 from test03 where a1=1 and a2=2 and a3=3 and a4=2;
理想情况下
where 和符合索引的顺序一样。
explain select a1,a2,a3,a4 from test03 where a4=1 and a3=2 and a2=3 and a1=2;
不推荐!运气好而已
有一个SQL优化器帮你改完之后二者是等价的
//4是无效查询,所以要using where
//a4需要回表查询
explain select a1,a2,a3,a4 from test03 where a1=1 and a2=2 and a4=3 order by a3;
拼起来还是有序的1 2 3
explain select a1,a2,a3,a4 from test03 where a1=1 and a4=3 order by a3;
拼起来不是1 2 3
//理论上不会的
explain select a1,a2,a3,a4 from test03 where a1=1 and a4=3 order by a2, a3;
where 和order by
where后面要和索引顺序一致,不一致的话,后面部分会失效,用orderby语句和列平起来后还是顺序的也是可以的
案例
单表优化
1 创建一个表格
create table book(
bid int(4) primary key,
name varchar(20) not null,
authorid int(4) not null,
publicid int(4) not null,
typeid int(4) not null
);
insert into book values(1,'java',1,1,2);
insert into book values(2,'javaScrip',2,3,4);
insert into book values(3,'wx',3,5,7);
insert into book values(4,'C++',4,6,1);
commit;
查询authorid=1typeid为2或3的bid
explain select bid from book where typeid in(2,3) and authorid=1 order by typeid desc;
type=all extra是using filesort
优化:加索引
alter table book add index idx_bta(bid,typeid,authorid);
根据sql实际解析的顺序,调整索引的顺序
--索引一旦废弃优化,要删除旧的索引
drop index idx_bta on book;
--虽然可以回表,但是加入可以使用using index;
alter table book add index idx_atb(authorid,typeid,bid);
再次优化(之前是index)
//范围查询in有时候会失效,所以可以调整范围查询在后面
explain select bid from book where authorid=1 and typeid in(2,3) order by typeid desc;
--小结
- 最佳做前缀,索引不能跨列使用,保持索引的定义和使用顺序一致
- 索引需要多部优化
- 将in查询放到where条件的最后,防止失效
- authroid在索引里面,不需要回原表,但是in会使得typeid失效
多表优化
创建表格
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) primary key,
cname varchar(20)
);
insert into course2 values(1,'java');
insert into course2 values(2,'python');
insert into course2 values(3,'cotlin');
commit;
两表关联左连接
select * from teacher2 t left outer join course2 c on t.cid=c.cid where c.cname='java';
小表:10
大表:300
for(int i=0;i<小表.length;i++){
for(int j=0;j<大表.length;j++){
。。。
}
}
for(int i=0;i<大表.length;i++){
for(int j=0;j<小表.length;j++){
。。。
}
}
一般建议外层循环应该小,内存循环应该大
想加索引where 小表.x = 大表.x;
alter table teacher2 add index index_teacher2_cid(cid);
alter table course2 add index index_course2_cname(cname);
建议
- 当编写on t.cid =c.cid的时候,应该是将数据量小的表放在左边
- 索引应该放在经常使用的字段上,因此将x字段加上索引,一般是放在左边的表加索引
三表优化
a. 小表驱动大表
b. 索引建立在索引经常查询的字段上
避免索引失效的一些原则
- 符合索引的时候,不要跨列或无序使用
index:(a,b,c)
where a... and c... order by c
- 尽量使用全索引匹配
//所有索引都要用
index:(a,b,c)
where a... and c... order by c
如果a失效了b和c失效
- 不要再索引上进行任何操作(会失效)
计算,函数,类型转换,否则索引失效
select ... where A.x =
//不要
select ... where 3*A.x =
select * from book where authroid=1 and typeid=2;
- 复合索引不能使用 != 或者is null,否则自身和右侧索引全部失效
- 实际使用有没有SQL优化,但是实际上可能只有一个,优化是一个概率层面的。
体验一下概率事件
sql优化器是一个概率上的事件
- 有大于号可能也会失效
- 大部分情况都适用,但是sql优化器等原因,所以不是百分百的确定,范围查询之后的索引失效(> < in)
- 补救。尽量使用索引覆盖 using index,这个条件永远成立。
- like尽量用常量开头,不要用%开头,否则索引失效。如果必须使用模糊查询,可以使用索引覆盖进行挽救
explain select tname from teacher where tname like '%x%';
- 尽量不要使用类型转换
程序底层可能会将123 -> '123',索引失效 -
尽量不要使用or,否则失效
具体的优化方法
exists和in
如果主查询的数据很大,使用in
如果子查询的数据很大,使用exist,校验是否有数据
(前面大用)
select * from teacher where tname in (select id from teacher);
(后面大用exists)
select tname from teacher where exists (select * from teacher);
order by优化
经常看到using filesort,有两种算法:双路排序、单路排序
之前的是双路排序
(读取磁盘数据,进行排序buffer上)
(只用读取一次,将所有字段在buffer上面进行排序)
默认的是单路排序
如果数据量太大,会进行分片读取
注意:单路排序非常消耗buffer,如果数据量太大,可以调大buffer的大小
set max_length_for_sort_data=1024;
如果buffer太低,就会使得单路 变成双路
- 选择单路,调整buffer大小
- select a,b from 不要用*
- 复合索引,不要跨列使用
- 保证排序的一致性(都是升序或者降序)
sql排序-慢查询日志:mysql提供的日志记录,用户记录响应超过阈值的sql语句,慢查询日志,默认是关闭的,开发的时候可以打开
show variables like '%slow_query_log%';
开启,临时开启:
set global slow_query_log = 1;