MySQL数据库调优之关联查询、排序查询、分页查询、子查询、Group by优化

关联查询优化

1.准备工作

CREATE TABLE IF NOT EXISTS `type`(
   id INT(10) UNSIGNED NOT NULL  AUTO_INCREMENT,
   card INT(10) UNSIGNED NOT NULL,
   PRIMARY KEY(id)

);

CREATE TABLE IF NOT EXISTS book(
bookid INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
card INT(10) UNSIGNED NOT NULL,
PRIMARY KEY(bookid)
)

INSERT INTO TYPE(card) VALUES (FLOOR (1+(RAND()*20)));


INSERT INTO book(card) VALUES (FLOOR (1+(RAND()*20)));

情况1:左外连接

EXPLAIN SELECT SQL_NO_CACHE * FROM `type` LEFT JOIN book ON type.card=book.card;

在这里插入图片描述
添加索引后

CREATE INDEX Y ON book(card);

在这里插入图片描述
内连接

EXPLAIN SELECT SQL_NO_CACHE * FROM `type` INNER JOIN book ON type.card=book.card;

在这里插入图片描述
对于内连接来说,查询优化器可以决定谁作为驱动表,谁作为被驱动表出现的

删除被驱动表book的index后
在这里插入图片描述
对于内连接来说,如果表的连接条件中只能有一个字段有索引,则有索引的字段所在的表会被作为被驱动表出现
在这里插入图片描述
对于内连接来说,在两个表的连接条件都存在索引的情况下,会选择小表作为驱动表。“小表驱动大表”

join语句的原理

驱动表和被驱动表
驱动表是主表,被驱动表是从表,非驱动表。
对于内连接来说:

SELECT * FORM A JOIN B ON...

A一定是驱动表么? 不一定,优化器会根据你查询语句做优化,决定先查那张表,先查询的那张表就是驱动表,反之就是被驱动表。通过explain关键字可以查看。

对于外连接来说:

SELECT * FROM A LEFT JOIN B ON ...
SELECT * FROM B RIGHT JOIN A ON ....

通常会认为A为驱动表,B为被驱动表,但也未必

Simple Nested-Loop Join(简单嵌套循环连接)

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

Index Nested-Loop join (索引嵌套循环连接)

**
index nested-loop join其优化的思路主要是为了减少内层表数据的匹配次数,所以要求·被驱动表上必须有索引才行。通过外层表匹配条件直接与内层表索引进行匹配,避免和内层表的每条记录去进行比较,这样极大的减少了对内层表的匹配次数。

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

Block Nested Loop Join(块嵌套循环连接)

在这里插入图片描述
JOIN BUFFER缓冲区缓存的不只是关联表的列,select后面的列也会缓存起来
在这里插入图片描述
在这里插入图片描述
参数设置
block_nested_loop=on

SHOW VARIABLES LIKE  '%optimizer_switch%'
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on

join_buffer_size 默认256K

SHOW VARIABLES LIKE  '%join_buffer_size%'

在这里插入图片描述
JOIN小结
在这里插入图片描述

Hash Join
从Mysql的8.0.20版本开始将废弃BNLJ,因为从Mysql8.0.18版本开始就加入了hash join,默认都是用hash join

在这里插入图片描述
JOIN连接 小结
保证被驱动表的JOIN字段已经创建了索引
需要JOIN的字段,数据类型保持绝对的一致
left join时,选择小的作为驱动表,大表作为被驱动表。减少外层循环的次数
inner join 时,mysql会自动将小结果集的表选为驱动表 选择相信mysql优化策略。
能够直接多表关联的尽量直接关联,不用子查询(减少查询的趟数)
不建议使用子查询,建议将子查询SQL拆开结合程序多次查询,或使用JOIN来代替子查询。
衍生表建不了索引

子查询优化

Mysql从4.1版本开始支持子查询,使用子查询可以进行SELECT语句的嵌套查询,即一盒SELECT查询的结果作为另外一个SELECT 语句的条件。子查询可以一次性完成很多逻辑上需要多个步骤才能完成的SQL操作
子查询是Mysql的一项重要的功能,可以帮助我们通过一个SQL语句实现比较复杂的查询。但是,子查询的执行效率不高。原因
1.执行子查询时,Mysql需要为内层查询语句的查询结果建立一个临时表,然后外层查询语句从临时表中查询记录。查询完毕后,再撤销这些临时表。这样会消耗过多的CPU和IO资源,产生大量的慢查询。
2.子查询的结果集存储的临时表,不论是内存临时表还是磁盘临时表都不会存在索引,索引查询的性能会有一定的影响。
对于返回结果集比较大的子查询,其对查询性能的影响也越大。
在Mysql中,可以使用连接(JOIN)查询来代替子查询。连接查询不需要建立临时表其速度比子查询要快。如果查询中有使用索引的话,性能就会更好。

尽量不要使用NOT IN 或者NOT EXISTS,用LEFT JOIN xxxxx ON xx WHERE xx IS NULL 替代

排序优化

问题:在where条件字段上加索引,但是为什么在Order by字段上还要加索引呢?
回答
在mysql中,支持两种排序方式,分别是FileSortIndex排序
Index排序中,索引可以保证数据的有序性,不需要再进行排序,效率更高
FileSort排序则一般在内存中进行排序,占用CPU较多,如果待排结果较大,会产生临时文件I/0到磁盘进行排序的情况,效率更低。
优化建议:
1.SQL 中,可以在Where子句和Order子句中使用索引,目的时在WHERE子句中避免全表扫描,Order By子句避免使用FileSort排序。当然在某些情况下,全表扫描或者FileSort排序不一定比索引慢。但总的来说,我们还是要避免,以提高查询效率。
2.尽量使用Index完成Order by排序。如果Where和Order by后面是相同的列就使用单索引列;如果不同就使用联合索引。
3.无法使用Index时,需要对FileSort方式进行调优。
select的查询内容没有限制
在这里插入图片描述

select查询内容与索引保持一致(索引覆盖)
在这里插入图片描述
增加limit过滤条件,使用上了索引
在这里插入图片描述
order by时顺序错误,索引失效
在这里插入图片描述
在这里插入图片描述
上述案例违反了索引的最左匹配的原则
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上述三种情况,索引有在使用中

order by 时规则不一致,索引失效(顺序错,不索引;方向反,不索引)

EXPLAIN SELECT * FROM student ORDER BY age DESC,classid ASC LIMIT 10;

EXPLAIN SELECT * FROM student ORDER BY classid DESC,NAME ASC LIMIT 10;

EXPLAIN SELECT * FROM student ORDER BY age ASC,classid DESC LIMIT 10;

EXPLAIN SELECT * FROM student ORDER BY age DESC,classid DESC LIMIT 10;


只要最后一种倒着来的使用上了索引

无过滤,不索引


#无过滤,不索引

EXPLAIN SELECT * FROM student WHERE age=45 ORDER BY classid; #先使用where 过滤数据 ken_len=5

EXPLAIN SELECT * FROM student WHERE age=45 ORDER BY classid,NAME; #先使用where 过滤数据 ken_len=5

EXPLAIN SELECT * FROM student WHERE classid=45 ORDER BY age; #没用

EXPLAIN SELECT * FROM student WHERE classid=45 ORDER BY age LIMIT 10; #用了索引

小结
在这里插入图片描述
在这里插入图片描述
结论:
1.两个索引同时存在,mysql会自动选择最优方案。但是,随着数据量的变化,选择的索引也会随之变化
2.当【范围条件】和【group by或者order by】的字段出现二选一时,优先观察条件字段的过滤数量,如果过滤的数据足够多,而需要排序的数据并不多时,优先把索引放在范围字段上,反之,亦然。

fileSort算法:双路排序和单路排序

排序的字段若如果不在索引列上,则filesort会有两种算法:双路排序和单路排序

在这里插入图片描述
在这里插入图片描述
Order by时select 是一个大忌,最好只query需要的字段
原因:
当query的字段大小总和小于
max_length_for_sort_data*,而且排序的字段不是TEXT|BLOB类型时,会用改进的算法–单路排序,否则用老算法–多路排序.
两种算法的数据都有可能超出sort_buffer_size的容量,超出之后,会创建tmp文件进行合并排序,导致多次I/0,但是用单路排序的风险更大一些,所以要提高sort_buffer_size的容量

Group By优化

group by 使用索引的原则几乎与order by一致,group by即使没有过滤条件使用到索引,也可以直接使用索引。
group by 先排序再分组,遵循索引创建的最佳左前缀法则
当无法使用索引列时,增大max_length_for_sort_data和sort_buffer_size的参数设置
where的效率高于having,能写在where 限定的条件,就不要写在having中了。

减少使用order by,和业务沟通,能不排序就不排序,或者将排序放在程序端去做。

order by\group by\distinct 这些语句比较耗费CPU,数据库的CPU资源是宝贵的。

包含order by\group by\distinct 这些查询的语句,where条件过滤出来的结果集请保持在1000行以内,否则SQL会很慢。

优化分页查询

一般分页查询时,通过创建覆盖索引能够比较好的提高性能。一个常见又比较头疼的问题就是limit 2000000,10 此时,需要mysql排序前20000010条记录,仅仅返回2000000-20000010的记录,其他记录丢弃,查询排序的代价非常的大。

EXPLAIN SELECT * FROM student  LIMIT 2000000,10;

优化思路1:
索引上完成排序分页操作,最后根据主键关联回原表查询所需要的其他列的内容

EXPLAIN SELECT * FROM student t,(SELECT id FROM student ORDER BY id LIMIT 2000000,10) a WHERE t.id=a.id;

在这里插入图片描述
优化思路二:
改方案适合于主键自增的表,可以把limit查询转换成某个位置的查询

EXPLAIN SELECT * FROM student  WHERE id> 2000000 LIMIT 10;

在这里插入图片描述

Exists和In的区别

问题:
不太理解哪种情况下应该使用EXISTS,哪种情况应该用IN,选择的标准是看能否使用表的索引么?
回答:
索引是一个前提,其实选择与否还是要看表的大小。可以将选择的标准理解为小表驱动大表。在这种方式下效率是高的。

在这里插入图片描述

Count(*)与Count(具体字段)效率

问题: 在mysql中统计数据表的行数,可以使用三种方式:SELECT COUNT(*)\SELECT COUNT(1)和SELECT COUNT(具体字段),使用三者之间的查询效率是怎么样的?
前提: 如果要统计的是某个字段的非空数据行数,则另当别论,毕竟比较执行效率的前提是结果是一样的。
在这里插入图片描述

关于SELECT (*)

在表查询中,建议明确字段,不要用作为查询的字段列表,推荐使用SELECT <字段列表> 查询。
原因:
mysql在解析的过程中,会通过查询数据字典
按序转化为所有列名,这样会大大的耗费资源和时间。无法使用覆盖索引

LIMIT 1 对优化的影响

针对的是会扫描全表的SQL语句,如果你可以确定结果集只有一条,那么加上limit 1 时**,当找到结果的时候就不会继续扫描了,这样会加快查询速度**。

如果数据表已经对字段建立了唯一索引,那么可以使用索引进行查询,不会全表扫描的话,就不需要加上limit 1了

多使用COMMIT

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

李宏毅2023机器学习作业1--homework1——python语法

# 定义list del_col del_col [0, 38, 39, 46, 51, 56, 57, 64, 69, 74, 75, 82, 87] # 删除raw_x_train中del_col的列&#xff0c;axis为1代表删除列 raw_x_train np.delete(raw_x_train, del_col, axis1) # numpy数组增删查改方法 # 定义列表get_col get_col [35, 36, 37,…

openssl3.2 - 编译 - zlib.dll不要使用绝对路径

文章目录 openssl3.2 - 编译 - 编译时的动态库zlib.dll不要使用绝对路径概述测试zlib特性在安装好的目录中是否正常笔记70-test_tls13certcomp.t80-test_cms.t对测试环境的猜测从头再编译测试安装一次测试一下随便改变位置的openssl用到zlib时是否好使测试一下随便改变位置的op…

【爬虫逆向实战篇】定位加密参数、断点调试与JS代码分析

文章目录 1. 写在前面2. 确认加密参数3. 加密参数定位4. XHR断点调试 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xff01; 【作者推荐】&#xff1a;对JS逆向…

实战一个 Jenkins 构建 CI/CD流水线 的简单配置过程哈

引言&#xff1a;上一期我们讲述了gitlabCI/CD工具的介绍&#xff0c;工具之争&#xff0c;本期我们介绍Jenkins CI/CD 目录 一、Jenkins介绍 1、Jenkins概念 2、Jenkins目的 3、特性 4、产品发布流程 二、安装Jenkins 1、安装JDK 2、安装Jenkins 1、上传压缩包 2、…

(done) 如何判断一个矩阵是否可逆?

参考视频&#xff1a;https://www.bilibili.com/video/BV15H4y1y737/?spm_id_from333.337.search-card.all.click&vd_source7a1a0bc74158c6993c7355c5490fc600 这个视频里还暗含了一些引理 1.若 AX XB 且 X 和 A,B 同阶可逆&#xff0c;那么 A 和 B 相似。原因&#xff1…

北航复试知识点总结

2024.2.25 住行 报道+机试+两天面试=4天 面试流程 (每个人大概20min,早一点到考场!) 形式:5位老师(一记录,四提问) 老师 陆峰 办公地址:北京航空航天大学新主楼H1033 电子邮箱: lufeng@buaa.edu.cn 个人主页:http://shi.buaa.edu.cn/lufeng/ 面试礼仪 于无形中…

编曲学习:高叠和弦 挂留和弦 和弦实战应用

高叠和弦 挂留和弦 和弦实战应用小鹅通-专注内容付费的技术服务商https://app8epdhy0u9502.pc.xiaoe-tech.com/live_pc/l_65d4826fe4b04c10a1310517?course_id=course_2XLKtQnQx9GrQHac7OPmHD9tqbv 七和弦 以三和弦举例,三和弦上面叠一个三度的音,就变成了七和弦。 从下到…

Spring Boot利用Kaptcha生成验证码

生成验证码 我们在登录或注册某个网站的时候&#xff0c;会需要我们输入验证码&#xff0c;才能登录注册&#xff0c;那么如何生成验证码呢&#xff1f;其实&#xff0c;生成验证码我们可以用Java Swing在后台内存里的区域画一个出来&#xff0c;但是非常麻烦&#xff0c;所以…

WIFI EEPROM 简略分析-MT7628 EEPROM ANALYSIS

经常做WIFI的同学都了解,硬件设计完成后经过射频的测试满足设计要求后,在量产以及生产中都需要对WIFI的射频需要校准,保证产品射频输出功率的一致性。 在开发阶段就必须需要了解WIFI的EEPROM都是一些什么参数,一般在硬件开发阶段会拿到芯片厂家都SDK,里面都包含对EEPROM的…

用什么软件制作电子杂志

想要制作高大上的电子杂志&#xff1f;别再烦恼啦&#xff01;今天给大家推荐一款超级实用的软件&#xff0c;让你轻松制作出专业水准的电子杂志&#xff01; 这款软件功能强大&#xff0c;操作简单&#xff0c;适合所有对设计感兴趣的小伙伴们。无论是新手还是专业设计师&…

代码随想录算法训练营第二十五天 | 216.组合总和III,17.电话号码的字母组合 [回溯篇]

代码随想录算法训练营第二十五天 LeetCode 216.组合总和III题目描述思路参考代码总结 LeetCode 17.电话号码的字母组合题目描述思路参考代码 LeetCode 216.组合总和III 题目链接&#xff1a;216.组合总和III 文章讲解&#xff1a;代码随想录#216.组合总和III 视频讲解&#xff…

javascript监听浏览器离开、进入行为

document.addEventListener(visibilitychange, () > {if (document.visibilityState hidden) {alert(离开)}if (document.visibilityState visible) {alert(进入)}}) visibilitychange是浏览器新添加的一个事件&#xff0c;当其选项卡的内容变得可见或被隐藏时&#xff0…

React组件通讯

组件通讯 组件是一个独立的单元&#xff0c;默认情况下组件只能自己使用自己的数据。在组件化过程中&#xff0c;我们将一个完整的功能拆分成多个组件&#xff0c;便于更好的完成整个应用的功能。 Props 组件本来是封闭的&#xff0c;要接受外部数据应该可以通过Props来实现…

opencv图像处理

// 提取路口轮廓集合&#xff08;每个路口的轮廓为一系列点集&#xff09; std::vector<std::vector<cv::Point>> node_contours; std::vector<cv::Vec4i> node_hierarchy;保存轮廓的层次关系// 只提取外轮廓 轮廓近似方法&#xff1a;水平垂直对角线只保留端…

CSP-202209-3-防疫大数据

CSP-202209-3-防疫大数据 解题思路 一、数据结构定义 对于大模拟的题&#xff0c;合适的数据结构选择十分重要&#xff0c;正确的数据结构选择能够有效的提升解题效率 // 漫游消息结构体 struct RoamingData {int date, user, region; };vector<RoamingData> roamin…

C#与VisionPro联合开发——TCP/IP通信

TCP/IP&#xff08;传输控制协议/互联网协议&#xff09;是一组用于在网络上进行通信的通信协议。它是互联网和许多局域网的基础&#xff0c;为计算机之间的数据传输提供了可靠性、有序性和错误检测。在软件开发中&#xff0c;TCP/IP 通信通常用于实现网络应用程序之间的数据交…

YOLOv5算法进阶改进(17)— 添加BiFormer注意力机制 | 提升小目标检测精度

前言:Hello大家好,我是小哥谈。本文主要通过对YOLOv5模型添加Bifommer注意力机制为例,让大家对于YOLOv5模型添加注意力机制有一个深入的理解,通过本文你不仅能够学会添加Biformer注意力机制,同时可以举一反三学会其他的注意力机制的添加。🌈 前期回顾: YOLOv5算法进…

2024Node.js零基础教程(小白友好型),nodejs新手到高手,(八)NodeJS入门——http模块

一念心清净&#xff0c;处处莲花开。 055_http模块_网页资源加载基本过程 哈喽&#xff0c;大家好&#xff0c;这一课节我们来介绍一下网页资源加载的基本过程。首先先强调一点&#xff0c;这个内容对于我们后续学习非常非常的关键&#xff0c;所以大家务必要将其掌握。 首先先…

hbuilderx创建、运行uni-app

创建uni-app 在点击工具栏里的文件 -> 新建 -> 项目&#xff1a; 选择uni-app类型&#xff0c;输入工程名&#xff0c;选择模板&#xff0c;点击创建&#xff0c;即可成功创建。 uni-app自带的模板有 Hello uni-app &#xff0c;是官方的组件和API示例。还有一个重要模…

人人都是项目管理者,项目管理的基础入门

一、教程描述 本套教程旨在系统介绍项目管理的方法论&#xff0c;帮助大家认识、熟悉、体验、思考项目管理&#xff0c;全面掌握项目管理的流程与方法&#xff0c;快速成长为时代紧缺型的项目管理人才。本套项目管理入门教程&#xff0c;大小805.40M&#xff0c;共有13个文件。…