优化慢SQL

慢SQL的优化,主要从两个方面考虑,SQL语句本身的优化,以及数据库设计的优化。

1.避免不必要的列

SQL查询的时候,应该只查询需要的列,而不要包含额外的列,像 select * 这种写法就应该尽量避免。
这种方式会浪费CPU内存资源也会加剧网络消耗,同时也可能导致索引失效。

2.分页优化

在数据量比较大,分页比较深的情况下,需要考虑分页的优化。

select * from student where age=18 order by id asc limit 10000,10

索引覆盖

select id, age from student where age=18 order by id asc limit 10000,10

id偏移量

偏移量就是找到 limit 第一个参数对应的主键值,根据之歌逐渐值再去过滤并limit

select * from student 
where age = 18 and id >= (select id from student where age=18 limit 100000,1) limit 10;

游标分页

使用上次查询的最大值来当作这次的查询条件

需要一个列来记录上一次查询的最大值(通常是主键),并且满足查询条件时主键需要是有序的
因为本次查询需要依赖上一次查询的主键最大值,因此分页查询只能是连续的,不能进行跳页(比如查完第1页直接查第21页)

select * from student where age=18 and id > 上次查询最大记录 limit 10;

延迟关联

先取出满足条件的id,然后通过id去重新关联。好处是id可以是不连续的

select * from student s 
inner join (select id tmp_id from student where age = 18 limit 10000,10) tmp on s.id = tmp_id

3.索引优化

利用索引覆盖

InnoDB 使用二级索引查询数据时会回表,但如果索引的叶节点中已经包含要查询的字段,那它就没必要再回表查询了,这就叫索引覆盖,可以简单的理解为查询列都是索引列。

alter table test add index idx_a_b(a, b);
select a, b from test where a='北京'; 

避免使用or != <> 查询

在早起MySQL版本使用or查询可能会导致索引失效,高版本引入了索引合并,解决了这个问题。但在实际使用中还是规范写法,能不用就少用。

id<>'abc' <===> id>'abc' or id<'abc'
-- 这是针对单一有索引的字段,对于多字段可用用union替代,那么语句就有一半可以走索引
id>'abc' or name<'abc' <===>   id>'abc'  union  name<'abc' 

避免列上的函数运算

下面的SQL语句就不会走索引

select * from test where id + 1 = 50;
select * from test where month(update_time) = 7; 

使用联合索引时,注意最左匹配原则

4.JOIN 优化

优化子查询

尽量使用 Join 语句来替代子查询,因为子查询时嵌套查询,而嵌套查询会新建一张临时表,而临时表的创建和销毁会占用一定的系统资源以及花费一定的时间,同时对于返回结果集比较大的子查询,其对查询性能的影响更大。

小表驱动大表

关联查询的时候,要拿小表去驱动大表,因为关联的时候,MySQL内部会遍历驱动表,再去连接被驱动表。

select name from 小表 left join 大表;

适当增加冗余字段

增加冗余字段可以减少大量的连表查询,因为多张表的连表查询性能很低,所以可以适当的增加冗余字段,以减少多张表的关联查询,这是以空间换时间的优化策略
比如:员工表里有员工信息以及所属部门ID,但有大量查询需要员工信息和部门名字,这时就可以在员工表中增加部门名称字段。一个记录购物信息的表,除了单价和数量,还可以增加一个总价的字段,虽然总价依赖于单价和数量,但在查询价格时可以直接输出从而减少计算量

避免使用JOIN 关联太多的表

《阿里巴巴Java开发手册》规定不要 join 超过三张表,第一 join 太多降低查询的速度,第二 join 的buffer会占用更多的内存

5.排序优化

利用索引扫描做排序
MySQL 有两种方式生成有序结果:一是对结果集进行排序的操作,二十按照索引顺序扫描得出的结果。索引是排好序的数据结构,因此查询结果自然是有序的。
但是如果索引无法覆盖查询所需列,就会每扫描一条记录回表查询一次,这个操作是随机IO,通常会比顺序全表扫描还慢,有时会直接放弃使用索引转为全表扫描。
因此,在设计索引时,尽可能使用同一个索引既满足排序又用于查找行。

-- 索引(a, b, c)
select b, c from test where a like 'abc%' order by b, c;
  • 23
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值