SQL慢查询优化方式

news2024/11/13 8:00:30

目录

一、SQL语句优化

1. 避免使用 SELECT * ,而是具体字段

2.避免使用 % 开头的 LIKE 的查询

3.避免使用子查询,使用JOIN

4.使用EXISTS代替IN

5.使用LIMIT 1优化查询

6.使用批量插入、优化INSERT操作

7.其他方式

二、SQL索引优化

1.在查询条件或者连接条件的列上建立索引

2.遵循最左前缀原则

3.避免在索引列上进行计算

4.使用覆盖索引

5.避免使用更新频繁的列作为索引

6.避免过多的列使用复合索引

7.定期维护索引

三、EXPLAIN分析查询


MYSQL优化一般从SQL语句开始优化,再分析索引,即使有了良好的索引,糟糕的查询语句也可能导致性能问题

优化查询语句可以帮助数据库更有效地利用现有的资源,减少不必要的开销。下面是几个关于如何从查询语句开始优化的步骤:

  1. 识别慢查询
  2. SQL优化
  3. 索引使用
  4. 使用 EXPLAIN 分析查询

一、SQL语句优化

不合理的SQL语句会导致:

  • 索引失效,无法使用索引
  • 全表扫描,因为数据库必须检查每一行数据以确定是否匹配
  • 对于大型表,这会导致性能问题资源消耗

下面的例子🌰以User表为例

CREATE TABLE User (
    user_id INT PRIMARY KEY,
    name VARCHAR(255),
    phone VARCHAR(20),
    email VARCHAR(255),
    role VARCHAR(50),
    address VARCHAR(255),
    birthday DATETIME
);

1. 避免使用 SELECT * ,而是具体字段

❌:索引失效,全表扫描

SELECT * FROM user

✅:节省资源、减少网络开销。可能用到覆盖索引,减少回表,提高查询效率

SELECT id,username,sex FROM user

📌原因:

  • 只取实际需要的字段,节省资源、减少网络开销。

  • 可能用到覆盖索引,减少回表,提高查询效率

覆盖索引和回表下文会详解,此处不做过多赘述

⚠️注意:为节省时间,下面的样例字段都用 SELECT * 代替了

2.避免使用 % 开头的 LIKE 的查询

❌:

SELECT * FROM User WHERE name LIKE '%echola';

✅:

SELECT * FROM User WHERE name LIKE 'echola%';

3.避免使用子查询,使用JOIN

SELECT * FROM User 
WHERE id IN (
    SELECT user_id 
    FROM Orders 
    WHERE status = 'completed');

✅:

SELECT u.* 
FROM User u JOIN Orders o ON u.id = o.user_id 
WHERE o.status = 'completed';

inner joinleft joinright join优先使用inner join

   三种连接如果结果相同,优先使用inner join(返回行数少),如果使用left join左边表尽量小(小表在前,大表在后)

  • inner join 内连接,只保留两张表中完全匹配的结果集;

  • left join会返回左表所有的行,即使在右表中没有匹配的记录;

  • right join会返回右表所有的行,即使在左表中没有匹配的记录

⚠️:表连接不宜太多,一般5个以内

4.使用EXISTS代替IN

虽然需避免子查询,但是某些情况下还是需要使用子查询,使用EXISTS代替IN可以提高查询效率

❌:

SELECT * FROM User 
WHERE id IN (
    SELECT user_id 
    FROM Orders 
    WHERE status = 'completed');

✅:EXISTS 找到第一个匹配项后就会停止搜索,而 IN 会遍历整个子查询结果集

SELECT * FROM User 
WHERE id EXISTS (
    SELECT user_id 
    FROM Orders 
    WHERE status = 'completed');

5.使用LIMIT 1优化查询

在只需要一条结果的查询中使用 LIMIT 1 可以提高性能,

尤其是在使用Mybatis Plus中的selectOne(),若有多条数据符合,则会抛出异常,因此需要添加 LIMIT 1

SELECT * FROM users WHERE name = 'echola' LIMIT 1;

6.使用批量插入、优化INSERT操作

使用批量插入可以减少事务提交次数:在批量插入过程中,尽量减少事务提交的次数。可以在一个事务中插入多条记录,然后一次性提交。在开发中一般使用MybatisPlus的saveBatch()

START TRANSACTION;
INSERT INTO User (user_id, name, phone, email, role, address, birthday)
VALUES
       (1, 'Alice', '1234567890', 'alice@example.com', 'user', 'New York', '2000-01-01 00:00:00'),
       (2, 'Bob', '0987654321', 'bob@example.com', 'admin', 'Los Angeles', '1999-01-01 00:00:00'),
       (3, 'Charlie', '5555555555', 'charlie@example.com', 'user', 'Chicago', '2001-01-01 00:00:00');
COMMIT;
   

7.其他方式

避免在 WHERE 子句中使用 OR 来连接条件

❌:

SELECT * FROM User WHERE age = 25 OR name = 'echola';

✅:

SELECT * FROM User WHERE age = 25
UNION ALL
SELECT * FROM User WHERE name = 'echola';

避免使用 NOT IN、!=、<> 等负条件,因为这些条件不能有效使用索引 

避免在索引列上使用IS NULLIS NOT NULL

避免使用HAVING代替WHERE,在可能的情况下,使用 WHERE 代替 HAVING 进行过滤,因为 HAVING 是在聚合之后进行过滤,性能较差

二、SQL索引优化

合理地使用索引是SQL最重要的

如果数据量小的表,可以不建立索引,但数据量大的表肯定是需要建立索引的

如果一张表上kw的数据量,果索引使用不当,也可能会导致索引失效,反而成为负担

以下关键词条解释:

复合索引:多个列组合成的索引

覆盖索引:索引中包含了查询所需的全部字段
最左前缀原则:在复合索引中,查询条件应尽可能地按照索引的顺序进行匹配

回表:当数据库使用索引来加速查询时,如果索引是非聚集索引(也称为辅助索引或者二级索引),那么索引项中存储的并不是完整的行数据,而是指向实际数据行的指针。当数据库通过索引查找到匹配的索引项后,还需要根据这个指针回到实际的数据页去获取完整的行数据

1.在查询条件或者连接条件的列上建立索引

⚠️:只要发现接口查询缓慢,优先检查 WHERE 后面的条件,有没有创建索引,如果已经建立索引,需要创建复合索引,调整现有索引

⚠️:索引不宜太多,一般5个以内

CREATE INDEX idx_userid ON User(user_id);
SELECT * FROM User WHERE user_id = 123 AND name = 'echola';

2.遵循最左前缀原则

对于复合索引(name, age, phone),可以用于(name),(name, age),(name, age, phone)顺序匹配查询

CREATE INDEX idx_name_age_phone ON User(name, age, phone);

❌:此处是(age,phone),没有按照索引的顺序进行匹配 ,导致索引无法完全利用,可能需要额外的回表操作

SELECT * FROM User WHERE age = 25 AND phone = '1234567890';

✅:按顺序匹配(name, age)

SELECT * FROM User WHERE phone = '1234567890' AND age = 25 ;

3.避免在索引列上进行计算

❌:使用 YEAR(date) 会导致索引失效

CREATE INDEX idx_birthday ON User(birthday);

SELECT * FROM User WHERE YEAR(birthday) = 2024;

✅:

SELECT * FROM User WHERE birthday BETWEEN '2024-01-01' AND '2024-12-31';

4.使用覆盖索引

如果查询的所有列都在索引中,那么数据库引擎可以不访问表中的数据而直接从索引中获取所需信息,这样可以减少回表操作,从而提高查询效率

❌:不使用覆盖索引

CREATE INDEX idx_userid ON User(user_id);

SELECT user_id, phone, role FROM User WHERE user_id = 123;

索引 idx_userid 只包含 user_id 列,但 user_id, phone, 和 role 列不在索引里,导致需要回表访问主键索引或其他索引

✅:索引中覆盖了所有查询的列,数据库可以直接从索引中获取数据

CREATE INDEX idx_userid_phone_role ON User(user_id, phone, role);

SELECT user_id, phone, role FROM User WHERE user_id = 123;

5.避免使用更新频繁的列作为索引

更新频繁的列作为索引会导致较高的维护成本,降低查询性能

❌:phone 列更新频繁,每次更新都会导致索引的重建,更新成本高,影响性能

CREATE INDEX idx_phone ON User(phone);

6.避免过多的列使用复合索引

复合索引的列数不要太多,列数过多会增加索引的维护开销,并且可能导致索引文件过大。对此可以拆分为较少复合索引和单个索引

CREATE INDEX idx_userid_phone_role_address ON User(user_id, phone, role, address);

7.定期维护索引

使用 ANALYZE TABLE 更新统计信息,并使用 OPTIMIZE TABLE 来整理碎片化的索引 ,特别是在大量插入、更新和删除操作后,表可能会出现碎片化,导致性能下降

ANALYZE TABLE User;
OPTIMIZE TABLE User;

⚠️:这两个命令可能会导致锁定表,因此在高并发环境中使用时要谨慎,最好在低峰时段执行

对于非常大的表,执行这些命令可能需要较长时间,建议提前进行测试

三、EXPLAIN分析查询

使用 EXPLAIN 分析 SQL 执行计划可以帮助我们理解数据库如何执行查询,并找出潜在的性能瓶颈

SELECT user_id, phone, role FROM User WHERE user_id = 123 AND birthday > '2000-01-01 

先看下没有建立索引的情况

EXPLAIN SELECT user_id, phone, role FROM User WHERE user_id = 123 AND birthday > '2000-01-01 00:00:00';

 执行结果:

具体解释:

EXPLAIN 输出表格包含多个列,每列提供不同的查询计划信息。常见列包括:

1、id:查询的标识符,表示查询的执行顺序

2、select_type:查询类型,如 SIMPLE(简单查询),PRIMARY(主查询),UNION(联合查询的一部分),SUBQUERY(子查询)

3、table:查询涉及的表

4、type:连接类型,表示MySQL如何查找行。常见类型按效率从高到低排列为:

  • system:表只有一行(常见于系统表)
  • const:表最多有一个匹配行(索引为主键或唯一索引)
  • eq_ref:对于每个来自前一个表的行,表中最多有一个匹配行。
  • ref:对于每个来自前一个表的行,表中可能有多个匹配行。
  • range:使用索引查找给定范围的行。
  • index:全表扫描索引。
  • ALL:全表扫描。

5、possible_keys:查询中可能使用的索引(user_id主键索引PRIMARY KEY)

6、key:实际使用的索引。

7、key_len:使用的索引键长度。

8、ref:使用的列或常量,与索引比较,此处表示常量引用,即 user_id = 123

9、rows:MySQL 估计的要读取的行数。

10、filtered:经过表条件过滤后的行百分比。

11、Extra:额外的信息,如 Using index(覆盖索引),Using where(使用 WHERE 子句过滤),Using filesort(文件排序),Using temporary(使用临时表)

建立复合索引

CREATE INDEX idx_userid_birthday ON User(user_id, birthday);

执行结果 :

 

主键索引使用:

        默认的主键索引 user_id 被利用,使得查询可以快速定位到 user_id = 123 的记录。
复合索引优化:

        创建复合索引 idx_userid_birthday 可以进一步优化查询性能,减少不必要的扫描操作。

通过这些步骤,我们可以确保查询性能得到显著提升,并且索引能够充分利用

欢迎对SQL优化的方式,进行补充……

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

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

相关文章

Java异常详解(全文干货)

介绍 Throwable Throwable 是 Java 语言中所有错误与异常的超类。 Throwable 包含两个子类&#xff1a;Error&#xff08;错误&#xff09;和 Exception&#xff08;异常&#xff09;&#xff0c;它们通常用于指示发生了异常情况。 Throwable 包含了其线程创建时线程执行堆栈…

分库分表学习笔记(二)

分库分表学习笔记&#xff08;一&#xff09;-CSDN博客 分表分库规则 图源&#xff08;https://zhuanlan.zhihu.com/p/535713197&#xff09; 水平分表 水平分表一般是我们数据库的数据太多了&#xff0c;原大众点评的订单单表早就已经突破两百G。 数据量太多的影响 1. 查询…

linux dma cache和主存数据不一致问题

1、问题原因 根本原因是cache和dma的目的地址存在重叠。 如果DMA的目的地址与Cache所缓存的内存地址访问有重叠&#xff08;如上图所示&#xff09; &#xff0c; 经过DMA操作&#xff0c; 与Cache缓存对应的内存中的数据已经被修改&#xff0c; 而CPU本身并不知道&#xff0c…

VScode开发ESP32

以下是所有的功能 先选择串口&#xff0c;再选择编译&#xff0c;然后再烧录

2023年最新自适应主题懒人网址导航v3.9php源码

源码简介 这个懒人网址导航源码是一个基于PHPMySQL开发的网址导航系统。该版本是在原有3.8版本的基础上进行了修复和功能增强。我们建议新用户直接使用这个最新版本&#xff0c;放弃旧版本。如果你有二次开发的能力&#xff0c;可以根据更新日志自行进行升级。我们将在后期继续…

论文阅读笔记:RepViT: Revisiting Mobile CNN From Vit Perspective

文章目录 RepViT: Revisiting Mobile CNN From Vit Perspective动机现状问题 贡献实现Block设置独立的token融合器和通道融合器减少膨胀并增加宽度 宏观设计stem的早期卷积简单分类器整体阶段比率 微观设计内核大小选择Squeeze-and-excitation层放置网络架构 实验ImageNet-1K上…

idea import配置

简介 本文记录idea中import相关配置&#xff1a;自动导入依赖、自动删除无用依赖、避免自动导入*包 自动导入依赖 在编辑代码时&#xff0c;当只有一个具有匹配名称的可导入声明时&#xff0c;会自动添加导入 File -> Settings -> Editor -> General -> Auto Imp…

基于xr-frame实现微信小程序的人脸识别3D模型叠加AR功能(含源码)

前言 xr-frame是一套小程序官方提供的XR/3D应用解决方案&#xff0c;基于混合方案实现&#xff0c;性能逼近原生、效果好、易用、强扩展、渐进式、遵循小程序开发标准。xr-frame在基础库v2.32.0开始基本稳定&#xff0c;发布为正式版&#xff0c;但仍有一些功能还在开发&#…

笔试——双指针算法

双指针&#xff1a; 把数组下标看作指针&#xff0c;注意数组越界问题&#xff0c;注意区间边界值 文章目录 283.移动零1089.复写零 283.移动零 class Solution {public void moveZeroes(int[] nums) {int cur 0;int dest -1;while(cur < nums.length)if(nums[cur] ! 0)…

uni-app开发日志:schema2code生成的新增页和修改页因字段太多用分段器实现分段分类

schema2code默认只能实现较为简单的分组&#xff0c;当填写项目较多的时候&#xff0c;肯定是用选项卡明确分段比较合适&#xff0c;这时候schema2code自生成的就没法实现了&#xff0c;摒着最最少的代码修改来尝试设置生成前的schema和生成后的vue页面。 一、schema设计 先把…

ORA-16072: a minimum of one standby database destination is required

原因 Doc ID 260819.1 The problem is that these Data Guard protection mode will not allow the database to be opened without a Standby Database available and a corresponding setup log_archive_dest_n. Therefore the Data Guard Protection Mode must be reduced…

MATLAB 地面点构建三角网(83)

MATLAB 地面点构建三角网(83) 一、算法介绍二、算法实现1.代码一、算法介绍 使用少量的抽稀后的地面点。构建了一层2.5维的三角网,用于表示地形的起伏变化,随着点数量增多,构建和耗时都会相应增加,这里只是输出和研究三角网构建效果,并不做实际工程使用,具体的构建结果…

在容器 (podman) 中运行虚拟机 (QEMU/KVM, libvirt)

虚拟机 (virtual machine) 是一种计算机的虚拟化技术, 容器 (container) 是一种更轻量级的虚拟化技术. 虚拟机可以套娃 (嵌套, nest), 也就是在虚拟机中运行虚拟机. 容器也可以套娃, 比如 Docker in Docker, Podman in Podman, Podman in Docker 等. 容器和虚拟机也可以互相套娃…

【云原生之kubernetes实战】k8s环境中部署Nginx服务

【云原生之kubernetes实战】k8s环境中部署Nginx服务 一、Nginx介绍1.1 Nginx简介1.2 Nginx特点1.3 Nginx使用场景二、本次实践介绍2.1 本次实践简介2.2 本次环境规划三、检查k8s环境3.1 检查工作节点状态3.2 检查系统pod状态四、部署storageclass(可选)4.1 配置NFS服务器4.2 …

Leetcode42接雨水(单调栈)

题目 题目链接 解法一 求出前缀最大和后缀最大&#xff0c;用两者较小值减去当前高度&#xff0c;累加即可&#xff0c;这个思路容易想到&#xff0c;这里不赘述 class Solution { public:int trap(vector<int>& height) {vector<int> preMx(height.size()…

故障检测(同相/反相放大器+电压跟随器)+概念(开环/闭环增益+增益的频率依赖性+3dB/单位增益带宽+增益-频率依赖性+相移)

2024-8-28&#xff0c;星期二&#xff0c;20:19&#xff0c;天气&#xff1a;阴雨&#xff0c;心情&#xff1a;晴。今天没什么事情发生&#xff0c;继续学习。 今天完成了第六章运算放大器的学习&#xff0c;开始了第七章运算放大器响应的学习&#xff0c;主要学习内容为&…

毕 业 设 计(论 文)远程接入企业网络规划与设计

毕 业 设 计&#xff08;论 文&#xff09; 远程接入企业网络规划与设计 毕业设计论文中文摘要 随着Internet技术的日益普及&#xff0c;网络技术的飞速发展&#xff0c;企业信息化工作越来越受到重视&#xff0c;进入二十一世纪后&#xff0c;企业信息化不再满足于个人或单…

使用WireShark的tshark命令,在window系统Cmd命令行抓包(附环境变量的设置)

WireShark在window系统Cmd命令行的抓包应用 工作中&#xff0c;有时候会遇到抓特定数据包的情况&#xff0c;但是却不知道这个特定数据包什么时候出现。因此就需要有设备值守抓包&#xff0c;这时就可以使用wireshark提供的tshark命令抓包。 一、抓包需求&#xff1a; 例如&am…

【虚拟化】KVM常用命令操作(virsh虚拟机常用操作之开关|连接|自启|克隆|快照)

目录 ​编辑一、KVM概述 1.1 KVM工具栈 1.2 libvirt架构概述 二、使用virsh管理虚拟机 三、kvm基本功能管理 1.帮助命令 2.KVM的配置文件存放目录 3.查看虚拟机状态 4.虚拟机关机与开机 5.强制虚拟机系统关闭电源 6.通过配置文件启动虚拟机系统 7.修改虚拟机配置文…

【项目实战】MobileNetV3 医学病理识别+不使用全连接预测+迁移学习+附代码数据教程

目录 简言. 环境搭建&快速开始 1. 数据集制作 2、训练教程 2.1 迁移学习 2.2 卷积自编码器,不使用全连接 2.3训练 3 实际推理 结果: 简言. 环境搭建&快速开始 大家好,我是cv君,今天带来以前的干货,mobilenet v3的优化,能在医学病理分类中得到优异准确率…