优化慢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;
相关推荐
好奇的菜鸟3 小时前
如何在IntelliJ IDEA中设置数据库连接全局共享
java·数据库·intellij-idea
tan180°3 小时前
MySQL表的操作(3)
linux·数据库·c++·vscode·后端·mysql
满昕欢喜3 小时前
SQL Server从入门到项目实践(超值版)读书笔记 20
数据库·sql·sqlserver
Hello.Reader4 小时前
Redis 延迟排查与优化全攻略
数据库·redis·缓存
简佐义的博客5 小时前
破解非模式物种GO/KEGG注释难题
开发语言·数据库·后端·oracle·golang
爬山算法5 小时前
MySQL(116)如何监控负载均衡状态?
数据库·mysql·负载均衡
JAVA学习通6 小时前
Mybatis--动态SQL
sql·tomcat·mybatis
老纪的技术唠嗑局8 小时前
OceanBase PoC 经验总结(二)—— AP 业务
数据库
阿里云大数据AI技术8 小时前
OpenSearch 视频 RAG 实践
数据库·人工智能·llm
m0_6239556610 小时前
Oracle使用SQL一次性向表中插入多行数据
数据库·sql·oracle