MySQL SQL 优化

news/2025/1/9 13:48:59/文章来源:https://www.cnblogs.com/Yee-Q/p/18655688

避免使用select *

反例:

select * from user where id=1;

在实际业务场景中,可能我们真正需要使用的只有其中一两列。此外,多查出来的数据,通过网络 IO 传输的过程中,也会增加数据传输的时间。最重要的一点是:select * 不走覆盖索引,会出现大量回表操作

正例:

select name,age from user where id=1;

小表驱动大表

1. join

MySQL 的 join 实现原理是:以驱动表的数据为基础,循环匹配被驱动表的记录

  • left join 前面的表是驱动表,后面的表是被驱动表
  • right join 后面的表是驱动表,前面的表是被驱动表
  • inner join / join 会自动选择表数据比较少的作为驱动表

假设 a 表 10000 条数据,b 表 20 数据,sql 如下:

select * from a join b on a.id = b.id

这里有两个过程,b 表数据最少,查询引擎优化选择 b 为驱动表:

  • 循环 b 表的 20 条数据
  • 根据条件(a.id = b.id)在 a 表的 10000 数据中匹配,找到符合条件的数据后组装返回

对被驱动表的 join 字段,也就是 b.id 建立索引,匹配时可以走索引,此时查找次数为:20 * log10000

如果反过来选择 a 为驱动表,同样的过程,此时查找次数为:10000 * log20

显然 20 * log10000 要远远小于 10000 * log20

就算没有对被驱动表的连接字段建立索引,建立 20 次链接和建立 10000 次链接消耗的资源也有天壤之别

2. in

sql 如下:

select name from a where id in (select id in b);

MySQL 会先执行子查询,再执行主查询。这里相当于先获取 b 表的所有 id,然后循环所有 id,以每一个 id 为条件去执行主查询,因此子查询选择小表

3. exists

sql 如下:

select name from b where exists (Select * from a where a.id=b.id);

MySQL 会先执行主查询,再执行子查询。这里相当于先获取 b 表的所有数据,然后循环所有数据,取 b.id 为条件执行子查询,若有匹配则返回,因此主查询选择小表


索引优化

控制索引数量,因为对表的数据做增删改操作时,需要同步更改索引,消耗额外的性能。建议单表的索引数量尽量控制在 5 个以内,单个索引的字段数不超过 5 个

使用 explain 检查索引性能,参考文章:https://www.cnblogs.com/Yee-Q/p/18066673

索引失效常见场景:https://www.cnblogs.com/Yee-Q/p/18103308


批量操作

例如一批数据需要插入表,逐条插入需要建立多次请求数据库,此时可以选择批量插入

insert into order(id,code,user_id) 
values(123,'001',100),(124,'002',100),(125,'003',101);

但不建议一次批量操作太多的数据,数据太多会导致数据库响应缓慢。建议每批数据尽量控制在 500 以内,如果数据多于500,则分多批次处理


高效分页

查询数据时,为了避免一次性返回过多的数据影响接口性能,一般会对查询接口做分页处理

MySQL 分页一般用 Limit 关键字:

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

随着页码增大,就会出现性能问题,因为 Limit 分页的原理是查出第一条到最后一条数据,再丢弃前面的数据。此时可以先记录上次分页最大的 id,然后根据 id 为条件查询,该方案要求 id 是有序的

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

还可以使用 Between 关键字实现分页,注意 id 要是连续的,不然会出现每页大小不一致的问题

select id,name,age 
from user where id between 1000000 and 1000020;

用连接查询代替子查询

MySQL 执行子查询时,需要创建临时表,查询完毕后再删除临时表,产生额外的性能消耗,这时可以改成连接查询

子查询的例子如下:

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

连接查询的例子如下:

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

优化 Group By 语句

group by 关键字的主要功能是去重和分组,通常跟 having 一起使用,表示分组后再根据一定的条件过滤数据

使用 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 条件分组前,把多余的数据过滤掉,这样分组效率就会更高一些


选择合理的字段类型

char 表示固定字符串类型,存储空间是固定的。varchar 表示变长字符串类型,存储空间会根据实际数据的长度调整。如果是长度固定的字段,比如用户手机号,可以定义成 char 类型,长度是 11 字节,如果是用户名称,使用 char 类型定义长度太长或太短都有可能出现问题,建议使用 varchar 类型

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

  • 能用数字类型,就不用字符串,因为字符的处理往往比数字要慢
  • 尽可能使用小的类型,比如:用 bit 存布尔值,用 tinyint 存枚举值等
  • 长度固定的字符串字段,用 char 类型
  • 长度可变的字符串字段,用 varchar 类型
  • 金额字段用 decimal,避免精度丢失问题

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VUE +WebSocket+speak-tt 实现在浏览器右下角实时给商家推送订单消息

先看效果 1、WebSocket服务建立1.1 引入包<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>1.2 新建配置类package com.ruoyi.web.core.config;import org.…

ASE65R180-ASEMI超洁MOS管ASE65R180

ASE65R180-ASEMI超洁MOS管ASE65R180编辑:ll ASE65R180-ASEMI超洁MOS管ASE65R180 型号:ASE100N10 品牌:ASEMI 封装:TO-220F 批号:最新 最大漏源电流:21A 漏源击穿电压:650V RDS(ON)Max:180mΩ 引脚数量:3 芯片个数: 沟道类型:P沟道MOS管、超洁MOS管 漏电流:ua 特性…

【搜索】DFS与BFS

99. 岛屿数量讲解:https://programmercarl.com/kamacoder/0099.岛屿的数量广搜.html#思路 DFS代码 #include <iostream> #include <cstring>using namespace std;const int N = 55;int n, m; int g[N][N]; bool st[N][N]; int dx[4] = {-1, 0, 1, 0}, dy[4] = {0,…

DFS与BFS专题

99. 岛屿数量讲解:https://programmercarl.com/kamacoder/0099.岛屿的数量广搜.html#思路 DFS代码 #include <iostream> #include <cstring>using namespace std;const int N = 55;int n, m; int g[N][N]; bool st[N][N]; int dx[4] = {-1, 0, 1, 0}, dy[4] = {0,…

Spinnaker

Spinnaker 是一个持续交付平台,它定位于将产品快速且持续的部署到多种云平台上。 Spinnaker 主要特性:配置一次,随时运行;随地部署,集中化管理;开源。 Spinnaker 组件:Spinnaker 最初是以实现内部的端到端持续交付为目标,作为 Asgard 的替代,该项目期望重建一个持续交…

Java基础学习(五)

Java基础学习(五):数组 目录Java基础学习(五):数组概念声明与创建初始化基本特点内存分析应用多维数组扩展内容Arrays 类冒泡排序稀疏数组 本文为个人学习记录,内容学习自 狂神说Java概念数组是相同类型数据的有序集合 每个数据称为一个数组元素,可以通过下标来访问声明…

CDS标准视图:付款锁定原因 I_PaymentBlockingReason

视图名称:付款锁定原因 I_PaymentBlockingReason 视图类型:基础视图 视图代码:点击查看代码 //Documentation about annotations can be found at http://help.sap.com searching for CDS annotations //Inserted by VDM CDS Suite Plugin @ObjectModel.usageType.sizeCateg…

欧拉OpenEuler使用nfs和rsync复制文件夹到新服务器.250109

案例: 服务器A是新服务器 服务器B为老服务器 需要将服务器B的/data/storage ,拷贝到服务器A的 /home/sync-data下一、服务器A 新服务器配置nfs 1. 安装nfs systemctl stop firewalld df -h mkdir -p /home/sync-datayum install nfs-utils systemctl status nfs-se…

在 .NET 9 中使用 Scalar 替代 Swagger

前言 在.NET 9发布以后ASP.NET Core官方团队发布公告已经将Swashbuckle.AspNetCore(一个为ASP.NET Core API提供Swagger工具的项目)从ASP.NET Core Web API模板中移除,这意味着以后我们创建Web API项目的时候不会再自动生成Swagger API文档了。那么今天咱们一起来试试把我们…

第九章 范围管理 (2025年详细解析版)

目录什么是范围管理?9.1 管理基础9.1.1 产品范围和项目范围9.1.2 产品范围和项目范围管理新实践9.2 项目范围管理过程9.2.1 过程概述9.2.2 项目范围管理过程9.2.3 裁剪考虑因素(了解)9.2.4 敏捷与适应方法总结9.3 规划范围管理1. 课程目标2. 过程定义:规划范围管…

Qt监控系统远程网络登录/请求设备列表/服务器查看实时流/回放视频/验证码请求

一、前言说明 这几个功能是近期定制的功能,也非常具有代表性,核心就是之前登录和设备信息都是在本地,存放在数据库中,数据库可以是本地或者远程的,现在需要改成通过网络API请求的方式,现在很多的服务器很强大,都提供了各种API接口,包括登录和拉取回放等,相当于直接对接…

debian10测试

https://help.aliyun.com/zh/ecs/user-guide/change-debian-9-or-10-repository-addresses?spm=a2c4g.11186623.0.0.52c44bccrP9uFq