MySQL慢SQL优化方案汇总

server/2024/9/23 22:40:19/

 a31da70afc294501ba5d6e07af20bd59.jpeg

⛰️个人主页:     蒾酒

🔥系列专栏sql>mysql经验总结》

🌊山高路远,行路漫漫,终有归途


目录

写在前面

优化思路

避免查询不必要的列

分页优化

索引优化

JOIN优化

排序优化

UNION 优化

写在最后


写在前面

本文介绍了MySQL常见的优化慢sql的手段,坚持看完相信对你有帮助。

同时欢迎订阅MySQL系列专栏,持续分享MySQL的使用经验。

优化思路

sql的优化无非是从两个方向着手

  • SQL语句本身的优化
  • 据库设计的优化

下面进行渐进式的分享一些常见优化手段

避免查询不必要的列

查询应该精准的查出需要的列,对于select * 的写法要避免,因为所有字段查出来不仅sql查询执行慢,若是直接返回给前端,大量的数据也会影响网络传输效率。

分页优化

对于数据量特别大,这时分页会比较深,查询扫描的数据量会比较大效率自然低,我们就需要进行分页优化

假设我们有一个包含大量订单记录的订单表,其中每个订单都有一个唯一的不包含业务逻辑的主键,并且我们想要查询最近一个月的订单并按照订单id从小到大进行分页显示某页。

假设出现深分页的sql如下:

sql">select * from orders where order_date >= date_sub(now(), interval 1 month)order by id limit 100000, 10;

执行此SQL时需要先扫描到100000行,然后再去取10行,但是随着扫描的记录数越多,SQL的性能就会越差,因为扫描的记录越多,MySQL需要扫描越多的数据来定位到具体的多少行,这样耗费大量的 IO 成本和时间成本。

对于解决该深分页问题通常有两种方法

1.延迟关联

先通过 where 条件提取出主键,在将该表与原数据表关联,通过主键 id 提取数据行,而不是通过原来的二级索引提取数据行

优化后sql:

sql">select o.*
from (select idfrom orderswhere order_date >= date_sub(now(), interval 1 month)order by idlimit 100000, 10
) as sub
join orders as o on sub.id = o.id;

优化后SQL中的子查询只取主键id,可避免通过二级索引中的主键去回表查询,这样性能会快一些。

2.id偏移量

偏移量就是找到 limit 第一个参数对应的主键值,根据这个主键值再去过滤并 limit,这种方法又称为基于游标的分页。基于游标的分页的前提是需要保证主键或排序列的连续性、唯一性。

优化后sql:

sql">select *
from orders
where id >= (select id from orders order by id limit 100000, 1)
order by id
limit 10;

这种方法相对于原来直接使用偏移量和限制结果数量的方式,可以在大数据集上提供更稳定和一致的性能,因为它不需要扫描和跳过大量的行。

索引优化

通过合理的设计和使用索引,能够有效优化sql性能,这也是我们使用最多的手段。

下面介绍一下如何进行索引优化:

使用覆盖索引

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

示例:

sql">select product_name, price
from products
where category_id = 1;
sql">create index idx_category_id on products (category_id, product_name, price);

避免使用or查询

在 MySQL 5.0 之前的版本要尽量避免使用 or 查询,可以使用 union 或者子查询来替代,因为早期的MySQL版本使用 or 查询可能会导致索引失效,高版本引入了索引合并,解决了这个问题,不过建议大家在实际使用中还是规范写法,能不用就少用。

避免使用 != 或者 <>操作符

SQL中,不等于操作符会导致查询引擎放弃查询索引,引起全表扫描,即使比较的字段上有索引。解决方法:通过把不等于操作符改成 or,可以使用索引,避免全表扫描

sql">id <>'aaa'
sql">id >'aaa'or id<'aaa

适当使用前缀索引

适当地使用前缀索引,可以降低索引的空间占用,提高索引的查询效率。比如,邮箱的后缀都是固定的“@xxx.com”,那么类似这种后面几位为固定值的字段就非常适合定义为前缀索引

sql">create index idx_email_prefix on users (email(6)); -- 假设后缀长度为6

需要注意的是,前缀索引也存在缺点,MySQL无法利用前缀索引做 order by和 group by 操作,也无法作为覆盖索引。

避免列上函数运算

要避免在列字段上进行算术运算或其他表达式运算,否则可能会导致存储引擎无法正确使用索引,从而影响了查询的效率。

sql">select order_id
from orders
where total_amount / 2 > 100

正确使用联合索引

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

JOIN优化

优化子查询

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

小表驱动大表

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

sql">select name from小表 left join 大表;

适当增加冗余字段

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

避免使用 JOIN 关联太多的表

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

排序优化

利用索引扫描做排序

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

sql">#索引为 a,b,c
select b,c from test where a like 'aa%' order by b,c;

只有当索引的列顺序和 ORDER BY 子句的顺序完全一致,并且所有列的排序方向都一样时,才能够使用索引来对结果做排序。

UNION 优化

条件下推

MySQL处理 union 的策略是先创建临时表,然后将各个查询结果填充到临时表中最后再来做查询,很多优化策略在 union 查询中都会失效,因为它无法利用索引。所以需要将 where、limit 等子句下推到 union 的各个子查询中,以便优化器可以充分利用这些条件进行优化。

此外,除非确实需要服务器去重,一定要使用 union all,如果不加 all 关键字,MySQL 会给临时表加上distinct 选项,这会导致对整个临时表做唯一性检查,代价很高。

写在最后

MySQL优化慢SQL的6种方式到这里就结束了,本文介绍了常见慢sql优化的有效方式。任何问题评论区或私信讨论,欢迎指正。


http://www.ppmy.cn/server/10831.html

相关文章

南京邮电大学数学实验A 作业2 矩阵代数 答案 | 《MATLAB数学实验》第三版 第三章 课后习题答案

若要获得更好的阅读体验,请前往 链接。 1(课本习题1) 设a=(1, 2, 3), b=(2, 4, 3), 分别计算a./b, a. \b, a/b, a \b,分析结果的意义. 答: a./b: a中的每一个元素除以b中的对应元素 a.\b: b中的每一个元素除以a中的对应位置的元素 a/b: a左除b,即矩阵方程ax=b的解 a\…

SpringBoot如何集成MyBatis可以通过几个简单的步骤来实现

在SpringBoot中集成MyBatis可以通过几个简单的步骤来实现。以下是一个基本的步骤指南&#xff1a; 步骤1&#xff1a;添加依赖 首先&#xff0c;你需要在你的pom.xml文件中添加MyBatis和数据库的依赖。例如&#xff0c;如果你使用MySQL数据库&#xff0c;你可以添加以下依赖&…

一文读懂企业内部wiki:含义、作用、如何搭建

在如今这个信息化、数字化的时代&#xff0c;许多公司的知识管理工具发展成了必不可少的企业内部wiki。那么&#xff0c;什么是企业内部wiki&#xff0c;它的作用是什么&#xff1f;应该如何搭建&#xff1f;这就是今天我们要来说的三个问题。一起来看看。 一、企业内部wiki的含…

数据结构OJ:设计循环队列

题目介绍 本题为LeetCode上的经典题目&#xff0c;题目要求我们设计一种循环队列&#xff0c;满足FIFO原则且队尾被连接在队首之后。 思路讲解 题目中介绍循环队列的好处是可以重复利用空间&#xff0c;所以我们很容易想到在初始化时即开辟指定大小的空间&#xff0c;之后便不…

vue纯前端实现表格分页及条件查询功能

由于接口返回数据过慢&#xff0c;故而采用前端对数据进行处理分页的方法实现表格分页及条件查询。 一、表格 表格采用elementUI的el-table&#xff0c;只需要对数据data进行处理赋值即可。 <el-table:data"tableData"style"width: 100%"><el-t…

SIMRAD AP48 自动舵控制器维修用于 Continuum 自动驾驶仪系统Simrad显示器仪器深圳捷达工控维修

AP48 自动驾驶仪控制器是一款用于 Continuum 自动驾驶仪系统的高级专用控制头&#xff0c;采用现代玻璃舵造型进行了增强。 AP48 专为各种条件下的响应能力和易用性而设计&#xff0c;将大型铝制旋转控制旋钮与专用的“闪避键”配对&#xff0c;以 1 度或 10 度的增量调整左舷…

智能时代 | 合合信息Embedding模型荣获C-MTEB榜单第一

目录 前言 1. MTEB与C-MTEB 2. acge模型的优势 3. Embedding模型应用 4. 大模型发展的关键技术 结语 前言 随着人工智能的不断发展&#xff0c;大语言模型吸引着社会各界的广泛关注&#xff0c;支撑模型应用落地的Embedding模型成为业内的焦点&#xff0c;大模型的发展给…

【Ubuntu20.04】在ubuntu 中执行 systemd status 查询到的 Memory 的含义及方法

在 Ubuntu 中&#xff0c;使用 systemd 管理的服务&#xff0c;其内存相关的状态信息通常指的是服务运行时占用的内存。当您查询一个 systemd 服务的资源使用情况时&#xff0c;获取到的内存数据反映的是该服务在运行过程中实际使用的内存大小。这包括服务进程及其子进程所分配…