优化慢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;
相关推荐
2601_9495936518 分钟前
深入解析CANN-acl应用层接口:构建高效的AI应用开发框架
数据库·人工智能
javachen__18 分钟前
mysql新老项目版本选择
数据库·mysql
Dxy123931021636 分钟前
MySQL如何高效查询表数据量:从基础到进阶的优化指南
数据库·mysql
Dying.Light39 分钟前
MySQL相关问题
数据库·mysql
蜡笔小炘1 小时前
LVS -- 利用防火墙标签(FireWall Mark)解决轮询错误
服务器·数据库·lvs
韩立学长1 小时前
基于Springboot泉州旅游攻略平台d5h5zz02(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·旅游
Re.不晚2 小时前
MySQL进阶之战——索引、事务与锁、高可用架构的三重奏
数据库·mysql·架构
老邓计算机毕设2 小时前
SSM智慧社区信息化服务平台4v5hv(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm 框架·智慧社区、·信息化平台
麦聪聊数据2 小时前
为何通用堡垒机无法在数据库运维中实现精准风控?
数据库·sql·安全·低代码·架构
2301_790300962 小时前
Python数据库操作:SQLAlchemy ORM指南
jvm·数据库·python