【MYSQL】MYSQL 的学习教程(九)之 23 个 SQL 优化小技巧

news2025/2/6 20:09:50

这篇文章从 15 个方面,分享了 sql 优化的一些小技巧,希望对你有所帮助

目录

  • 1. 避免使用 select *,务必指明字段名称
  • 2. 用 union all 代替 union
  • 3. 小表驱动大表
  • 4. 批量操作
  • 5. 当只需要一条数据的时候,使用limit 1
  • 6. IN 包含的值不应过多
  • 7. 增量查询
  • 8. 高效的分页
  • 9. 用连接查询代替子查询
  • 10. join 的表不宜过多
  • 11. join 时要注意
  • 12. 控制索引的数量
  • 13. 选择合理的字段类型
  • 14. 提升 group by 的效率
    • WHERE 和 HAVING 区别
  • 15. 如果排序字段没有用到索引,就尽量少排序
  • 16. 如果限制条件中其他字段没有索引,尽量少用 or
  • 17. 避免在 where 子句中对字段进行 null 值判断
  • 18. 避免在 where 子句中对字段进行表达式操作
  • 19. 不建议使用%前缀模糊查询
  • 20. 避免隐式类型转换
  • 21. 对于联合索引来说,要遵守最左前缀法则
  • 22. 索引优化
  • 23. 必要时可以使用 force index 来强制查询走某个索引

1. 避免使用 select *,务必指明字段名称

在实际业务场景中,可能我们真正需要使用的只有其中一两列。查了很多数据,但是不用,

  1. 白白浪费了数据库资源,比如:内存、cpu
  2. 多查出来的数据,通过网络 IO 传输的过程中,也会增加数据传输的时间
  3. 不会走覆盖索引,会出现大量的回表操作,而从导致查询 sql 的性能很低

【优化】:sql 语句查询时,只查需要用到的列,多余的列根本无需查出来

2. 用 union all 代替 union

  • sql 语句使用 union 关键字后,可以获取排序、去重后的数据
  • union all 关键字,可以获取所有数据,包含重复的数据

排序、去重的过程需要遍历、排序和比较,它更耗时,更消耗 cpu 资源

【优化】:如果能用 union all 的时候,尽量不用 union。除非是有些特殊的场景,比如业务场景中是不允许产生重复数据的

3. 小表驱动大表

小表驱动大表:用小表的数据集驱动大表的数据集

假如有 order 和 user 两张表,其中 order 表有 10000 条数据,而 user 表有 100 条数据
这时如果想查一下,所有有效的用户下过的订单列表

可以使用 in 关键字实现:

select * from order
where user_id in (select id from user where status=1)

也可以使用 exists 关键字实现:

select * from order
where exists (select 1 from user where order.user_id = user.id and status=1)

这种业务场景,使用 in关键字去实现业务需求,更加合适。

  • 因为如果 sql 语句中包含了 in 关键字,则它会优先执行 in 里面的子查询语句,然后再执行 in 外面的语句。如果 in 里面的数据量很少,作为条件查询速度更快
  • 而如果 sql 语句中包含了 exists 关键字,它优先执行 exists 左边的语句(即主查询语句)。然后把它作为条件,去跟右边的语句匹配。如果匹配上,则可以查询出数据。如果匹配不上,数据就被过滤掉了

【总结】:

  • in 适用于左边大表,右边小表
  • exists 适用于左边小表,右边大表

4. 批量操作

不建议一次批量操作太多的数据,如果数据太多数据库响应也会很慢。批量操作需要把握一个度,建议每批数据尽量控制在 500 以内。如果数据多于 500,则分多批次处理

5. 当只需要一条数据的时候,使用limit 1

有时候,我们需要查询某些数据中的第一条,使用 limit 1

6. IN 包含的值不应过多

sql 语句如下:

select id,name from category
where id in (1,2,3...100000000);

如果我们不做任何限制,该查询语句一次性可能会查询出非常多的数据,很容易导致接口超时。

①:使用 limit 做限制:

select id,name from category
where id in (1,2,3...100)
limit 500;

②:代码层面校验

public List<Category> getCategory(List<Long> ids) {
   if(CollectionUtils.isEmpty(ids)) {
      return null;
   }
   if(ids.size() > 500) {
      throw new BusinessException("一次最多允许查询500条记录")
   }
   return mapper.getCategoryList(ids);
}

③:分批查询
如果 ids 超过 500 条记录,可以分批用多线程去查询数据。每批只查 500 条记录,最后把查询到的数据汇总到一起返回(这只是一个临时方案,不适合于ids实在太多的场景。因为 ids 太多,即使能快速查出数据,但如果返回的数据量太大了,网络传输也是非常消耗性能的,接口性能始终好不到哪里去)

7. 增量查询

有时候,我们需要通过远程接口查询数据,然后同步到另外一个数据库

如果直接获取所有的数据,然后同步过去。这样虽说非常方便,但是带来了一个非常大的问题,就是如果数据很多的话,查询性能会非常差

【优化】:

select * from user 
where id> #{lastId} and create_time >= #{lastCreateTime} 
limit 100;

按 id 和时间升序,每次只同步一批数据,这一批数据只有 100 条记录。每次同步完成之后,保存这 100 条数据中最大的 id 和时间,给同步下一批数据的时候用

通过这种增量查询的方式,能够提升单次查询的效率

8. 高效的分页

在 mysql 中分页一般用的 limit 关键字:

select id,name,age 
from user limit 10,20;

如果表中数据量少,用limit关键字做分页,没啥问题。但如果表中数据量很多,用它就会出现性能问题

【优化】:

select id,name,age 
from user where id > 1000000 limit 20;

先找到上次分页最大的 id,然后利用 id 上的索引查询。不过该方案,要求id是连续的,并且有序的

9. 用连接查询代替子查询

mysql 中如果需要从两张以上的表中查询出数据的话,一般有两种实现方式:子查询 和 连接查询

子查询的例子如下:

select * from order
where user_id in (select id from user where status=1)

子查询语句可以通过 in 关键字实现,一个查询语句的条件落在另一个 select 语句的查询结果中。程序先运行在嵌套在最内层的语句,再运行外层的语句

子查询语句的优点是简单,结构化,如果涉及的表数量不多的话

但缺点是 mysql 执行子查询时,需要创建临时表,查询完毕后,需要再删除这些临时表,有一些额外的性能消耗

【优化】:
这时可以改成连接查询。具体例子如下:

select o.* from order o
inner join user u on o.user_id = u.id
where u.status=1

10. join 的表不宜过多

根据阿里巴巴开发者手册的规定,join 表的数量不应该超过 3 个

如果 join 太多,mysql 在选择索引的时候会非常复杂,很容易选错索引,并且如果没有命中中,nested loop join 就是分别从两个表读一行数据进行两两对比,复杂度是 n^2

所以我们应该尽量控制 join 表的数量

如果实现业务场景中需要查询出另外几张表中的数据,可以在 a、b、c 表中冗余专门的字段,比如:在表 a 中冗余 d_name 字段,保存需要查询出的数据

11. join 时要注意

join 使用最多的是 left joininner join

  • inner join:mysql 会自动选择两张表中的小表,去驱动大表,所以性能上不会有太大的问题
  • left join:mysql 会默认用 left join 关键字左边的表,去驱动它右边的表。如果左边的表数据很多时,就会出现性能问题

用 left join 关联查询时,左边要用小表,右边可以用大表。如果能用 inner join 的地方,尽量少用 left join

12. 控制索引的数量

阿里巴巴的开发者手册中规定,单表的索引数量应该尽量控制在 5 个以内,并且单个索引中的字段数不超过 5 个

mysql 使用的 B+ 树的结构来保存索引的,在 insert、update和delete 操作时,需要更新 B+ 树索引。如果索引过多,会消耗很多额外的性能

高并发系统如何优化索引数量?

能够建联合索引,就别建单个索引,可以删除无用的单个索引

将部分查询功能迁移到其他类型的数据库中,比如:ElasticSeach、HBase 等,在业务表中只需要建几个关键索引即可

13. 选择合理的字段类型

我们在选择字段类型时,应该遵循这样的原则:

  1. 能用数字类型,就不用字符串,因为字符的处理往往比数字要慢。
  2. 尽可能使用小的类型,比如:用 bit 存布尔值,用 tinyint 存枚举值等。
  3. 长度固定的字符串字段,用 char 类型。
  4. 长度可变的字符串字段,用 varchar 类型

14. 提升 group by 的效率

有很多业务场景需要使用 group by 关键字,它主要的功能是去重和分组。通常它会跟 having 一起配合使用,表示分组后再根据一定的条件过滤数据

select user_id,user_name from order
group by user_id
having user_id <= 200;

这种写法性能不好,它先把所有的订单根据用户 id 分组之后,再去过滤用户 id 大于等于 200 的用户

分组是一个相对耗时的操作,为什么我们不先缩小数据的范围之后,再分组呢?

【优化】:

select user_id,user_name from order
where user_id <= 200
group by user_id

使用 where 条件在分组前,就把多余的数据过滤掉了,这样分组时效率就会更高一些

WHERE 和 HAVING 区别

  1. WHERE 指定行对应得条件, HAVING 指定组对应的条件
  2. 先执行 WHERE 子句,后执行 HAVING 子句

SQL 的执行顺序:

在这里插入图片描述

15. 如果排序字段没有用到索引,就尽量少排序

16. 如果限制条件中其他字段没有索引,尽量少用 or

or 两边的字段中,如果有一个不是索引字段,而其他条件也不是索引字段,会造成该查询不走索引的情况。很多时候使用 union all 或者是 union (必要的时候)的方式来代替“or”会得到更好的效果

17. 避免在 where 子句中对字段进行 null 值判断

对于null的判断会导致引擎放弃使用索引而进行全表扫描。

18. 避免在 where 子句中对字段进行表达式操作

对字段就行了算术运算,这会造成引擎放弃使用索引

19. 不建议使用%前缀模糊查询

例如LIKE “%name”或者LIKE “%name%”,这种查询会导致索引失效而进行全表扫描。但是可以使用LIKE “name%”。

那如何查询%name%?

答案:使用全文索引

20. 避免隐式类型转换

21. 对于联合索引来说,要遵守最左前缀法则

在创建联合索引的时候一定要注意索引字段顺序,常用的查询字段放在最前面

22. 索引优化

很多时候 sql 语句,走了索引,和没有走索引,执行效率差别很大。所以索引优化被作为 sql 优化的首选

  1. 查看是否建立索引
  2. 查看是否走了索引:EXPLAIN 查看执行计划:【MYSQL】MYSQL 的学习教程(七)之 慢 SQL 优化思路
  3. 如果建立索引但没有走索引,那么可能索引失效:【MYSQL】MYSQL 的学习教程(四)之索引失效场景

23. 必要时可以使用 force index 来强制查询走某个索引

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1336621.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows配置C语言环境(超级详细)

Windows配置C语言环境 1.安装C编译器&#xff08;MinGW-W64 GCC&#xff09;1.1点击安装1.2将压缩包解压到相应目录1.3把mingw添加进系统的环境变量1.4测试 2安装并配置Visual Studio Code2.1下载VSCode2.2“Code Runner”扩展的配置 3.编写C语言 各位小伙伴想要博客相关资料的…

初识Nginx默认配置文件

说起配置Nginx确实是一件让人头疼的事&#xff0c;开始时对Nginx配置不熟悉&#xff0c;为了满足需求在网上查找了很多相关配置的博客&#xff0c;也是天花乱坠不知道谁对谁错。就不停反复尝试最终在不懈的努力下中终于成功了。那时就觉得是时候好好整理一下Nginx的相关配置了。…

【MIMO 从入门到精通】[P6]【What is Beamforming?】

前言&#xff1a; Beamforming 是MIMO 技术里面的核心技术之一&#xff0c;所以讲MIMO 必须对Beamforming 有所了解&#xff0c;本篇主要了解一下beamforming Explains how a beam is formed by adding delays to antenna elements. 波束赋形&#xff08;Beamforming&#xff…

【我与java的成长记】之面向对象的初步认识

系列文章目录 能看懂文字就能明白系列 C语言笔记传送门 &#x1f31f; 个人主页&#xff1a;古德猫宁- &#x1f308; 信念如阳光&#xff0c;照亮前行的每一步 文章目录 系列文章目录&#x1f308; *信念如阳光&#xff0c;照亮前行的每一步* 前言一、什么是面向对象面向过程…

力扣刷题记录(18)LeetCode:474、518、377、322

目录 474. 一和零 518. 零钱兑换 II 377. 组合总和 Ⅳ 322. 零钱兑换 总结&#xff1a; 474. 一和零 这道题和前面的思路一样&#xff0c;就是需要将背包扩展到二维。 class Solution { public:int findMaxForm(vector<string>& strs, int m, int n) {vector&l…

tvbox最新接口配置

TVBox是在Github的开源项目&#xff0c;本身是一个空壳软件&#xff0c;可免费使用及再开发。安装后需要配置接口才能正常使用。 TVBox&#xff0c;也被称为网络电视盒子&#xff0c;是一种可以连接到电视的设备&#xff0c;使电视具有智能电视的功能。TVBox的主要功能是通过网…

mysql 26day 数据库双主双从 搭建mycat 数据库负载均衡 读写分离

目录 搭建一个(双主双从) &#xff08;然后搭建mycat&#xff09;四台主机配置master1 (主库1)master2 (主库2)slave 1(从库1)master1 (主库1)slave 1(从库1)如果配置出错 需要从这里从新配置 写入数据(测试)mycat安装java安装mycat编辑文件server.xml编辑文件schema.xml配置 m…

网站被恶意扫描怎么办(上WAF)

在网络安全领域&#xff0c;有一大类工具被广泛使用&#xff0c;且作用不可忽视&#xff0c;它就是网络安全扫描器。扫描器是一种专门设计用来评估计算机、网络或者应用中已知的弱点的计算机程序&#xff0c;但是很多人恶意使用&#xff0c;找到网站弱点进行攻击。 扫描器的种…

【csapp】cachelab

文章目录 Part APart B32 * 3264 * 6461 * 67 实验全程参考大佬的博客CS:APP3e 深入理解计算机系统_3e CacheLab实验 &#xff0c;感觉大佬在矩阵转置那块介绍的还是有些简略&#xff0c;我自己又做了点动图加以补充理解。膜拜大佬&#xff01; Part A 先解决解析命令行参数的…

fpga verilog rs232 发送模块实现

RS-232是一种串行通信协议&#xff0c;用于在计算机和其他外部设备之间进行数据传输。RS-232定义了电气特性、信号级别、机械特性和传输速率等规范&#xff0c;为串行通信提供了一种标准化的接口。 RS-232通常使用DB9连接器&#xff0c;用于传输和接收数据、控制信号以及地线连…

VMware17Pro虚拟机安装Linux CentOS 7.9(龙蜥)教程(超详细)

目录 1. 前言2. 下载所需文件3. 安装VMware3.1 安装3.2 启动并查看版本信息3.3 虚拟机默认位置配置 4. 安装Linux4.1 新建虚拟机4.2 安装操作系统4.2.1 选择 ISO 映像文件4.2.2 开启虚拟机4.2.3 选择语言4.2.4 软件选择4.2.5 禁用KDUMP4.2.6 安装位置配置4.2.7 网络和主机名配置…

小学班委有哪些职位

在成长的道路上&#xff0c;班委是一个不可或缺的角色。它不仅是一个职位&#xff0c;更是一份责任和担当。对于孩子们来说&#xff0c;成为班委不仅意味着荣誉&#xff0c;更意味着在集体中发挥自己的力量&#xff0c;为班级做贡献。 那么&#xff0c;小学班委有哪些职位呢&am…

小学班级管理方法和措施

开学了&#xff0c;宝贝们步入小学的大门&#xff0c;新环境、新同学、新起点。如何为孩子们营造一个和谐、有序的学习环境&#xff1f;这离不开我们班主任的精心管理。 制定明确的班规 教室里&#xff0c;同学们有秩序地坐着&#xff0c;这得益于我们班的班规。但班规不是摆设…

Java SPI 机制介绍和实战

目录 什么是 Java SPI Java SPI 原理 Java SPI 使用场景 1. 框架扩展与插件化 2. 服务加载与扩展 3. 组件化和模块化设计 4. 数据转换和格式化 5. 插件化应用程序 Java SPI 实战 步骤 1&#xff1a;定义服务接口 步骤 2&#xff1a;实现服务提供者 步骤 3&#xf…

UE5 C++(九)— 静态、动态加载类和资源

文章目录 前提静态加载类和资源静态加载资源静态加载类 动态加载类和资源动态资源动态加载类 前提 有必要说一下&#xff0c;静态这块内容加载时我用UE5.2版本出现调用静态资源不是显示问题&#xff0c;修改后容易崩。所以&#xff0c;这里不建议5.2版本&#xff0c;直接用5.3…

VS2005环境下编译C++报错

WinGenerateKey.obj : error LNK2011: 未链接预编译对象&#xff1b;映像可能不能运行 解决&#xff1a;连接器->输入&#xff0c;添加&#xff1a;..\WinGenerateKey\Debug\stdafx.obj 或者 ..\WinGenerateKey\Release\stdafx.obj 报错&#xff1a;fatal error C1083: Can…

【数据结构和算法】找到最高海拔

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 前缀和的解题模板 2.1.1 最长递增子序列长度 2.1.2 寻找数组中第 k 大的元素 2.1.3 最长公共子序列…

【WSL2】安装和配置ubuntu

文章目录 1. 安装WSL22. 安装ubuntu2.1. 通过Microsoft Store2.1. 通过命令行 3. ubuntu的使用3.1. 创建管理员root账户3.2. 换源3.3. 安装图形化界面GNOME 1. 安装WSL2 在控制面板 - 程序 - 程序与功能中点击启用或关闭Windows功能&#xff0c;选择 虚拟机平台适用于Linux的W…

阅读2023:让每一天都徜徉于书海之中

阅读&#xff0c;是中华民族的优良传统&#xff0c;也是创新发展的永续动力。2023年初&#xff0c;教育部、中央宣传部等八部门印发《全国青少年学生读书行动实施方案》&#xff0c;推动青少年学生阅读深入开展&#xff0c;促进全面提升育人水平。 阅读不仅是文化传承的重要手…