Mysql高级篇(中)—— SQL优化

news2024/11/13 7:55:07

SQL优化

  • 一、SQL优化的计划或思路
  • 二、关联查询优化
  • 三、子查询优化
  • 四、exists 和 not exists
    • 1、exists 介绍
    • 2、exists 和 not exists
  • 五、单路排序和多路排序(了解)
  • 六、排序分组优化
    • 1、order by
      • (1)避免临时排序,使用索引排序
      • (2)减少数据扫描
      • (3)调整 `MySQL` 参数配置
        • sort_buffer_size
        • max_length_for_sort_data
    • 2、group by

一、SQL优化的计划或思路

当生产环境中出现SQL语句执行耗时的问题时,为了确保系统的稳定性和性能,此时就需要我们快速分析和解决问题,首先是确认问题,通过查看慢查询日志来确认是哪些SQL语句导致的性能问题;其次通过explain 获取问题SQL的执行计划、通过show profile 进一步查询SQL 的执行细节和生命周期;最后深入分析与优化,数据库参数调优等措施来达到优化SQL的目的。具体思路参考下述内容:

在这里插入图片描述
在这里插入图片描述

二、关联查询优化

在优化关联查询时,只有在被驱动表建立索引才有效

  • left join 时,左侧的为驱动表,右侧为被驱动表
  • EXPLAIN:是判断驱动表被驱动表的最有效方法。通常,EXPLAIN 输出中第一行的表为驱动表,后面的为被驱动表
  • 表大小、索引、WHERE 子句 :影响优化器的选择。更小的表和带有索引的表更有可能成为驱动表
  • STRAIGHT_JOIN:可以强制指定驱动表被驱动表的顺序。
  • 子查询尽量不要放在被驱动表,有可能使用不到索引
  • left join时,尽量让实体表作为被驱动表
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三、子查询优化

范围判断时,尽量不要使用 not innot exists,使用 left join on xxx is null 代替

在这里插入图片描述
在这里插入图片描述

四、exists 和 not exists

1、exists 介绍

EXISTSSQL中用于检查 子查询结果是否返回数据的关键字。它常用于提升查询性能,尤其是在需要判断某个条件是否满足而返回实际数据时。


EXISTS的值为布尔类型,当子查询时返回结果集时,EXISTS返回TRUE,否则返回FALSE;可以理解为:

  • 将主查询的数据放到子查询中作为条件验证更具验证结果(truefalse)来决定主查询的数据是否保留。

子查询结果较大时,EXISTS可以有更好的性能

EXISTS基本用法示例
假设我们有两个表:customersorders,它们的结构如下:

-- customers表:
customer_id | customer_name
---------------------------
1           | John
2           | Mary
3           | Alice


-- orders表:
order_id | customer_id | order_date
------------------------------------
1001     | 1           | 2023-09-01
1002     | 2           | 2023-09-05
1003     | 1           | 2023-09-10

1.使用EXISTS查询是否存在订单
我们想查询是否有下过订单的客户,而不关心订单的具体信息。可以通过以下方式使用EXISTS

SELECT customer_name 
FROM customers c
WHERE EXISTS (
    SELECT 1 
    FROM orders o 
    WHERE o.customer_id = c.customer_id
);

  • 内部子查询SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id用于判断orders表中是否存在与当前customers表中某个customer_id对应的订单。
  • 如果存在匹配的记录,EXISTS返回TRUE,那么该客户就会出现在最终结果集中。
  • SELECT 1EXISTS中消耗表示返回任何实际数据,SQL引擎只关心是否有记录存在。

2.EXISTS比较IN 相同的查询,如果使用IN,则查询如下:

SELECT customer_name
FROM customers
WHERE customer_id IN (
    SELECT customer_id 
    FROM orders
);

INEXISTS区别:

  • IN会首先执行子查询,返回所有满足条件的customer_id,然后在外层查询中逐一进行匹配。这在子查询返回大量数据时,可能会造成性能问题。
  • EXISTS对于每一行外层查询,它会在层子查询中逐条检查是否存在满足条件的记录,一旦找到匹配的数据则停止检查,在随后的某些场景下性能会更优。

3.使用EXISTS过滤数据
例如,我们希望查询下一个订单的客户,但只关心订单日期在 2023 年 9 月 1 日之后的客户:

SELECT customer_name 
FROM customers c
WHERE EXISTS (
    SELECT 1 
    FROM orders o 
    WHERE o.customer_id = c.customer_id
      AND o.order_date > '2023-09-01'
);


  • 在此示例中,EXISTS不仅在检查是否存在与客户相关的订单,还通过添加日期条件进一步筛选匹配的订单。这样可以确保我们查询到的客户都是在特定日期之后下订单的客户。

4.使用NOT EXISTS
有时我们需要查询不存在关联数据的情况,那么就可以使用NOT EXISTS。假设我们要找出所有未下过订单的客户:

SELECT customer_name 
FROM customers c
WHERE NOT EXISTS (
    SELECT 1 
    FROM orders o 
    WHERE o.customer_id = c.customer_id
);

  • NOT EXISTS用于查找对应的没有订单记录的客户。它检查orders表中是否有与每个customers表中的customer_id匹配的记录。如果没有,客户就会被返回。

5.EXISTSJOIN的区别
对于某些查询,JOINEXISTS结果是相同的,但它们的执行方式不同。

-- JOIN查询

SELECT c.customer_name
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id;

-- EXISTS查询:
SELECT c.customer_name
FROM customers c
WHERE EXISTS (
    SELECT 1 
    FROM orders o 
    WHERE o.customer_id = c.customer_id
);

  • JOIN返回所有匹配的行,如果一个客户有多个订单,客户信息会重复返回多个,可能导致数据丢失。
  • EXISTS则仅检查是否存在匹配记录,它不会返回重复数据,因此不需要具体关联数据时,EXISTS更为合适。
  • 在数据量增大且表关联关系复杂时,EXISTS可能表现出更好的性能。

6.性能考虑
EXISTS的性能通常是领先的IN,特别是当子查询的结果集非常大时。因为:

  • EXISTS通常会停止扫描,一旦找到满足条件的记录即停止,而IN会首先执行子查询并返回所有结果,然后与外层查询匹配。
  • 数据库引擎在处理EXISTS时,通常可以更有效地优化查询,尤其是在子查询和外层查询相关联时

总结:

  • EXISTS是在子查询中非常有用的工具,适用于检查数据是否存在而不是返回具体值
  • 它在很多场景下,尤其是数据量大的时候,性能出色IN,因为它能够提前终止查询。
  • EXISTS虽然与JOIN的执行结果相同,但首先更适合需要检查是否存在数据而不关心返回值的场景。

2、exists 和 not exists

  • EXISTS:当子查询有至少一行数据时返回,返回TRUE,用于判断某些条是否存在。
  • NOT EXISTS:当子查询没有数据返回时,返回TRUE,用于判断某些记录是否不存在。

代码示例分析:假设我们有两个表:employeesdepartments

-- employees 表:
employee_id | employee_name | department_id
-------------------------------------------
1           | Alice         | 10
2           | Bob           | 20
3           | Carol         | 30
4           | David         | 20



-- departments表:
department_id | department_name
--------------------------------
10            | HR
20            | IT

1. 使用EXISTS
需求: 查询在部门表departments中存在关联记录的员工。

SELECT employee_name
FROM employees e
WHERE EXISTS (
    SELECT 1 
    FROM departments d
    WHERE d.department_id = e.department_id
);
  • 子查询SELECT 1 FROM departments d WHERE d.department_id = e.department_id会检查每个表中employee_id是否departments存在关联的部门。
  • 对于employees表中的每一行,数据库会执行一次子查询。只要有匹配的department_idEXISTS就返回TRUE
  • 结果会返回AliceBobDavid,因为他们的department_iddepartments表中存在。

2.使用NOT EXISTS
需求: 查询在部门表departments中没有关联记录的员工(即无部门的员工)。

SELECT employee_name
FROM employees e
WHERE NOT EXISTS (
    SELECT 1 
    FROM departments d
    WHERE d.department_id = e.department_id
);

  • NOT EXISTS反过来检查员工的department_id是否 没有departments表中匹配。
  • 当子查询SELECT 1 FROM departments d WHERE d.department_id = e.department_id没有返回结果时,NOT EXISTS返回TRUE
  • 结果会返回Carol,因为她的department_iddepartments表中不存在。

EXISTSNOT EXISTS 的区别和应用场景
在这里插入图片描述
在这里插入图片描述

-- 使用IN查询部门为IT员工:
SELECT employee_name 
FROM employees 
WHERE department_id IN 
(SELECT department_id 
   FROM departments 
  WHERE department_name = 'IT');


-- 使用EXISTS替代方案IN:
SELECT employee_name 
FROM employees e
WHERE EXISTS (
    SELECT 1 
    FROM departments d 
    WHERE d.department_id = e.department_id 
    AND d.department_name = 'IT'
);

在一些完成下的情况下,EXISTS可能比IN效率更高,因为EXISTS一旦找到匹配数据就会终止子查询,而IN需要先整个子查询。

总结

  • EXISTS:检查子查询是否 返回 数据,适用于想确认某个条件是否存在的情况。返回适合快速判断某条记录是否与另一条记录相关联,能够有效避免数据。
  • NOT EXISTS:用于检查子查询是否 不返回 数据,适合查找主表中没有匹配关联记录的情况。多用于查找孤立的数据

    在实际开发中,可以根据查询的复杂程度、数据规模和具体需求,合理选择使用EXISTSNOT EXISTS,以达到最佳的性能和精度。

五、单路排序和多路排序(了解)

单路排序和多路排序 是数据库在执行排序操作时,为应对不同数据规模和内存限制而采取的两种策略。


MySQL 默认使用单路排序(One-Way Sorting),但这取决于排序的数据量sort_buffer_size 的配置。

在这里插入图片描述

六、排序分组优化

1、order by

(1)避免临时排序,使用索引排序

MySQL在无法利用索引排序时,会使用临时表进行排序(Using filesort)。应尽量避免这种情况
在这里插入图片描述

(2)减少数据扫描

在这里插入图片描述

  • 无过滤,不索引where,limt 都相当于一种过滤条件,所以才能使用上索引;因为 没有过滤条件:全表扫描,索引无用

(3)调整 MySQL 参数配置

增大 sort_buffer_sizemax_length_for_sort_data 参数配置

sort_buffer_size

sort_buffer_size 参数 指定了排序操作可使用的内存缓冲区的大小。 当数据库需要对数据进行排序时,会使用这个缓冲区。如果缓冲区不够大,MySQL 可能需要在磁盘上进行排序操作,这会显著降低性能。

  • 默认值: 一般是256KB(视MySQL版本和配置而定)。

sort_buffer_size 不够大时

  • 如果排序操作的数据量超出了 sort_buffer_sizeMySQL 会将数据写入磁盘上的临时文件进行排序,这会显著降低查询性能,特别是在大量数据排序的情况下。
  • 增加 sort_buffer_size 可以减少磁盘 I/O 操作,提高排序速度,但设置得过大可能导致服务器内存资源耗尽,影响整体性能

注意事项

  • 适度调整: 增大 sort_buffer_size 可以提高排序性能,但要避免设置得过大,以免导致内存不足。通常,可以在测试环境中调整这个参数,观察对查询性能的影响,找到合适的大小。
  • 作用范围: sort_buffer_size 是会话级别的参数,可以为特定会话设置不同的大小,而不影响其他会话。你也可以在全局级别设置它,但是要小心,如果全局设置不当(例如,将 sort_buffer_size 设置得过大),可能会导致服务器内存消耗增加,影响到整个数据库服务器的性能
    在这里插入图片描述
max_length_for_sort_data

max_length_for_sort_data 参数作用是 限制数据进行排序时所能使用的最大数据长度,以避免对非常长的数据进行排序时带来的性能问题。 如:当排序的列包含非常大的数据(如文本、BLOB 等)时,使用 max_length_for_sort_data 可以限制排序数据的长度,避免性能下降。


> 假设我们有一个 documents 表,结构如下:
>  doc_id (主键) 
>  title 
>  content (文本类型,可能非常长)

-----------------------------------------------
SELECT * FROM documents ORDER BY content;
-----------------------------------------------
【解释】:这个查询会按照 content 列的内容进行排序,并返回所有文档。
-----------------------------------------------
【问题】:content 列可能包含非常长的文本,如果直接对完整的文本进行排序,可能会占用大量内存并导致性能问题。
-----------------------------------------------
【解决办法】:这个时候我们就可以使用 max_length_for_sort_data 参数可以限制在排序时最多考虑的数据长度。如果某一行的数据长度超过这个限制,数据库可能只使用部分数据来进行排序。

如:SET max_length_for_sort_data = 1024;

在这里插入图片描述

2、group by

group by 使用索引的原则几乎跟 order by 一致 ,唯一区别是 group by 即使没有过滤条件用到索引,也可以直接使用索引。

  • 索引的帮助:如果 GROUP BY 中的列上存在索引,数据库可以更快地对数据进行分组。索引可以使得在执行 GROUP BY 操作时,不需要先对所有数据进行排序或扫描整个表,而是直接利用索引的有序性来加速分组过程。
  • 索引的局限性:尽管索引可以帮助 GROUP BY 操作更高效,但它的作用不如在 WHERELIMIT 子句中的明显。GROUP BY 操作的效率还取决于数据的分布聚合方式等因素。例如,当表中的数据需要大量聚合计算时,索引可能不能显著加速这个过程。

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

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

相关文章

【LabVIEW】条件结构的使用

本篇文章记录LabVIEW条件结构的使用方法,希望我的分享能对你有所帮助! 一、实践项目 二、工程详解 1、考虑到输入的数值需要判断一下是否是在0-100之间,故使用“判定范围并强制转换”模块 2、设置数值表示法和上下限 3、验证判断 4、最终程…

(黑马点评)二、短信登录功能实现

2.1 基于传统Session实现的短信登录及其校验 2.1.1 基于Session登录校验的流程设计 2.1.2 实现短信验证码发送功能 请求接口/user/code请求类型post请求参数phone返回值无 /*** 发送手机验证码*/PostMapping("/code")public Result sendCode(RequestParam("ph…

前端框架对比和选择

​ 大家好,我是程序员小羊! 前言: 前端框架选择是前端开发中的关键决策,因为它影响项目的开发效率、维护成本和可扩展性。当前,最流行的前端框架主要包括 React、Vue 和 Angular。它们各有优劣,适用于不同…

wallpaper engine壁纸提取

下载提取软件RavioliGameTools_v2.10.zip https://pan.baidu.com/s/14ZCVw3ucRERsB-GGGoCOqQ 2.运行RExtractor.exe 3.Input file(s)、Output directory填好 4.勾选Allow scanning of unkown files 5.点击Start

智能办公新纪元:AI优秘圈引领未来工作方式

随着人工智能技术的不断进步,它已经开始渗透到我们工作与生活的每一个角落。在这一背景下,AI优秘圈以其创新的智能办公解决方案,正在重新定义企业的工作方式。本文将探讨AI优秘圈如何利用AI技术提升工作效率,降低成本,…

AI换脸等违法行为的最关键原因是个人隐私信息的泄露,避免在网络上发布包含个人敏感信息的照片。

文章目录 引言I 避免在网络上发布包含个人敏感信息的照片不要晒家门钥匙、车牌等照片。不要发布各种票据类的照片不要公布手持身份证或手持白纸照II 相关反制技术的开发和应用III 犯罪案例: 通过“换脸”伪造不雅照当事人犯罪团伙引言 当前AI换脸技术比较成熟,能支持视频通话…

25届和24届一样,涝的涝死旱的旱死

还是秋招 今天无意间翻到一篇帖子: 帖子提到自己的求职经历:想找个产品实习岗,但连实习岗都会要求有相关工作经历... 经典的"蛋生鸡,鸡生蛋"问题。 在经历了完整的秋招后,总的感觉是"涝的涝死&#xff…

基于MATLAB/Simulink的模型降阶方法介绍

降阶建模ROM(Reduced order modeling) 和模型降阶MOR(Model order reduction) 是降低全阶高保真模型的计算复杂性,同时在令人满意的误差范围内保持预期保真度的技术。 模型降阶技术可以解决科学计算邻域在建模仿真与工程应用中的几大痛点: 高保真模型计…

从工厂打螺丝到数据库专家(上)

可能是年纪大了,近期总是失眠!不知为何,这段时间心情烦躁时,特别喜欢听老歌,难道这是中年人的通病:都喜欢怀旧? 在数据库恢复订阅伙伴群,大家经常讨论,总是在回味过去&a…

文心一言 VS 讯飞星火 VS chatgpt (350)-- 算法导论24.1 1题

一、在图 24-4上运行Bellman-Ford算法,使用结点 z z z作为源结点。在每一遍松弛过程中,以图中相同的次序对每条边进行松弛,给出每遍松弛操作后的 d d d值和 π π π值。然后,把边 ( z , x ) (z,x) (z,x)的权重改为 4 4 4&#xf…

面试官:什么是CAS?存在什么问题?

大家好,我是大明哥,一个专注「死磕 Java」系列创作的硬核程序员。 回答 CAS,Compare And Swap,即比较并交换,它一种无锁编程技术的核心机制。其工作方式分为两步: 比较:它首先会比较内存中的某…

汉字转拼音工具类

一,汉字转成拼音大写首字母 public static String chineseToPinyin(String chinese) {//创建一个 StringBuilder 对象用于存储转换后的拼音。StringBuilder pinyin new StringBuilder();//创建一个汉语拼音输出格式对象。HanyuPinyinOutputFormat format new Han…

Redis-01 入门和十大数据类型

Redis支持两种持久化方式:RDB持久化和AOF持久化。 1.RDB持久化是将Redis的数据以快照的形式保存在磁盘上,可以手动触发或通过配置文件设置定时触发。RDB保存的是Redis在某个时间点上的数据快照,可以通过恢复RDB文件来恢复数据。 2.AOF持久化…

MySQL 中的 EXPLAIN 命令:洞察查询性能的利器

《MySQL 中的 EXPLAIN 命令:洞察查询性能的利器》 在 MySQL 数据库的使用中,优化查询性能是至关重要的一项任务。而 EXPLAIN 命令就是我们用来深入了解查询执行计划的强大工具。今天,我们就来一起探讨如何在 MySQL 中使用 EXPLAIN 命令&…

数据结构-3.2.栈的顺序存储实现

一.顺序栈的定义&#xff1a;top指针指向栈顶元素 1.图解&#xff1a; 2.代码&#xff1a; #include<stdio.h> #define MaxSize 10 //定义栈最多存入的元素个数 ​ typedef struct {int data[MaxSize]; //静态数组存放栈中元素int top; //栈顶指针 } SqStack; ​ int…

python mysql pymysql 数据库操作,常用脚本,个人小工具

起因&#xff0c; 目的: 整理 mysql 工具 启动数据库 检查服务器是否启动了: Get-Service -Name ‘mysql*’ 如果没启动的话&#xff0c;那么就启动: net start MySQL80 (最好是开启管理员权限) 1, 日常最常用的&#xff0c;创建连接 --> 查看所有数据库 —> 查看所有…

预处理、makefile、静动态库编写、nfs挂载、快捷命令

c查看预处理后的文件 查看执行后的汇编代码 预处理过程 静态库和动态库 静态库编写 实践 a 动态库生成 查找文件命令 动态库升级 链接的库找不到 命名要为linfun.so 执行时-lfun才能找到 系统会将lfun补充成libfun查找&#xff08;系统默认路径/user/lib/...&#xff09; 链…

C++:string 类详解

目录 简介 使用 初始化(构造函数、拷贝构造函数) 析构函数 赋值运算符重载(operator) 成员常量(npos) 运算符重载[ ](operator[ ]) size() 和 length() 迭代器( begin() 和 end() ) 范围 for 迭代器和范围 for 的比较 反向迭代器( rbegin() 和 rend() ) const 迭…

每日刷题(算法)

我们N个真是太厉害了 思路&#xff1a; 我们先给数组排序&#xff0c;如果最小的元素不为1&#xff0c;那么肯定是吹牛的&#xff0c;我们拿一个变量记录前缀和&#xff0c;如果当前元素大于它前面所有元素的和1&#xff0c;那么sum1是不能到达的值。 代码&#xff1a; #def…

elasticsearch实战应用

Elasticsearch(ES)是一种基于分布式存储的搜索和分析引擎&#xff0c;目前在许多场景得到了广泛使用&#xff0c;比如维基百科和github的检索&#xff0c;使用的就是ES。本文总结了一些使用心得体会&#xff0c;希望对大家有所帮助。 一、技术选型 说到全文搜索大家肯定会想到…