优化慢SQL

优化慢SQL

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

1.避免不必要的列

SQL查询的时候,应该只查询需要的列,而不要包含额外的列,像 select * 这种写法就应该尽量避免。

这种方式会浪费CPU内存资源也会加剧网络消耗,同时也可能导致索引失效。

2.分页优化

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

sql 复制代码
select * from student where age=18 order by id asc limit 10000,10

索引覆盖

sql 复制代码
select id, age from student where age=18 order by id asc limit 10000,10

id偏移量

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

sql 复制代码
select * from student 
where age = 18 and id >= (select id from student where age=18 limit 100000,1) limit 10;

游标分页

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

需要一个列来记录上一次查询的最大值(通常是主键),并且满足查询条件时主键需要是有序的

因为本次查询需要依赖上一次查询的主键最大值,因此分页查询只能是连续的,不能进行跳页(比如查完第1页直接查第21页)

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

延迟关联

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

sql 复制代码
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 使用二级索引查询数据时会回表,但如果索引的叶节点中已经包含要查询的字段,那它就没必要再回表查询了,这就叫索引覆盖,可以简单的理解为查询列都是索引列。

sql 复制代码
alter table test add index idx_a_b(a, b);
select a, b from test where a='北京'; 

避免使用or != <> 查询

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

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

避免列上的函数运算

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

sql 复制代码
select * from test where id + 1 = 50;
select * from test where month(update_time) = 7; 

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

4.JOIN 优化

优化子查询

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

小表驱动大表

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

sql 复制代码
select name from 小表 left join 大表;

适当增加冗余字段

增加冗余字段可以减少大量的连表查询,因为多张表的连表查询性能很低,所以可以适当的增加冗余字段,以减少多张表的关联查询,这是以空间换时间的优化策略

比如:员工表里有员工信息以及所属部门ID,但有大量查询需要员工信息和部门名字,这时就可以在员工表中增加部门名称字段。一个记录购物信息的表,除了单价和数量,还可以增加一个总价的字段,虽然总价依赖于单价和数量,但在查询价格时可以直接输出从而减少计算量

避免使用JOIN 关联太多的表

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

5.排序优化

利用索引扫描做排序

MySQL 有两种方式生成有序结果:一是对结果集进行排序的操作,二十按照索引顺序扫描得出的结果。索引是排好序的数据结构,因此查询结果自然是有序的。

但是如果索引无法覆盖查询所需列,就会每扫描一条记录回表查询一次,这个操作是随机IO,通常会比顺序全表扫描还慢,有时会直接放弃使用索引转为全表扫描。

因此,在设计索引时,尽可能使用同一个索引既满足排序又用于查找行。

sql 复制代码
-- 索引(a, b, c)
select b, c from test where a like 'abc%' order by b, c;
相关推荐
远歌已逝1 小时前
维护在线重做日志(二)
数据库·oracle
qq_433099403 小时前
Ubuntu20.04从零安装IsaacSim/IsaacLab
数据库
Dlwyz3 小时前
redis-击穿、穿透、雪崩
数据库·redis·缓存
工业甲酰苯胺5 小时前
Redis性能优化的18招
数据库·redis·性能优化
没书读了6 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
i道i6 小时前
MySQL win安装 和 pymysql使用示例
数据库·mysql
小怪兽ysl6 小时前
【PostgreSQL使用pg_filedump工具解析数据文件以恢复数据】
数据库·postgresql
武子康6 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
wqq_9922502777 小时前
springboot基于微信小程序的食堂预约点餐系统
数据库·微信小程序·小程序
爱上口袋的天空7 小时前
09 - Clickhouse的SQL操作
数据库·sql·clickhouse