SQL2

优化实例

创建一个表格

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优化

有一个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;
没有filesort

拼起来还是有序的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;
拼起来了1 2 3

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);

左表加上索引,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,否则失效


    使用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;

你可能感兴趣的:(SQL2)