《MySQL DBA 修炼之道》第五章 查询优化

《MySQL DBA 修炼之道》原文是在第六章 查询优化,博主觉得比较重要,所以想提前整理为一篇博文。

查询优化是研发人员比较关注也是疑问最多的领域。

基础知识

1. 查询优化的常用策略

一般的常用策略 优化数据访问、重写SQL、重新设计表、添加索引 4种。

(1)优化数据访问

应该尽量减少对数据的访问。一般有两个需要考虑的地方:应用程序减少对数据库的访问,数据库减少扫描的记录数。
例如:如果应用程序可以缓存数据,就可以不需要从数据库中直接读取数据。
例如:如果应用程序只需要几个列的数据,就没必要把所有列的数据全部读取出来,应该尽量避免 SELECT * FROM table_name语句。

慢查询日志中,如果Rows_examined这项值很高,实际上并不需要扫描大量的数据,这种情况下添加索引或者增加筛选条件都可以极大地减少记录扫描的行数。

(2)重写SQL
由于复杂查询严重降低并发性,因此为了让程序更加灵活与迅速,我们可以把复杂的查询分解为多个简单的查询。一般来讲,多个简单查询的总成本是小于一个复杂查询的。
对于需要进行大量数据的操作,可以分批执行,可以减少对生产系统产生的影响,从而缓解复制超时。

MySQL JOIN会严重降低并发性,对于高并发,高性能的服务,应该尽量避免连接太多表,如果可以,尽量在应用层就对影响性能的SQL实现分解。这样可以更加方便的缓存数据,更方便的迁移数据,扩展性好。

(3)重新设计库表
有些情况下,我们即使是重新SQL或添加索引也解决不了问题,这时候可能考虑更改表结构的设计。比如:增加缓存表,暂存统计数据,或者增加冗余列,以减少连接。优化的方向是反范式设计。(见上一章节)

(4)添加索引
生产环境中的问题,可能80%都是索引问题,所以优化好索引,就有了一个好的开始。

2. 各种语句的优化方案

(1)连接的优化(JOIN)

MySQL使用的是“Nested Loop Join”嵌套连接。
在这里插入图片描述
我们称tbl1为外部表/驱动表,tbl2为内部表。这种算法的成本与外部表与内部表的乘机是成正比的。如果嵌套的层次比较多,也就是说连接了很多表,那么成本是很昂贵的。MySQL一般会选择小表做驱动表,为了减少连接嵌套循环的连接次数,而且内部表一般在连接列上有索引,索引一般常驻在内存,查询速度能快点。

由于连接的成本比较高,因此对于高并发的应用应该尽量减少连接的查询,连接表不能太多,最好不要超过4个。可以考虑反范式设计减少表的连接,或者考虑应用层进行连接。
1)最好能将LEFT JOIN转变为INNER JOIN。
2) 使用EXPLAIN检查连接,留意ROWS列,值太高就要考虑优化索引或连接。
3)反范式设计,适当的反范式设计可以减少连接次数,
4)考虑应用层实现连接,将复杂的查询在业务层转化为简单的多个查询,还便于经过缓存存取数据。

(2)GROUP BY、DISTINCT、ORDER BY语句优化

  • 尽量对较少的行进行排序
  • 如果连接了多张表,ORDER BY、GROUP BY的列应该属于连接列的驱动表
  • 利用索引排序。
  • 要保证索引列和ORDER BY的列相同,且各列均按照相同的方式进行排序。
  • 增加sort_buffer_size
    sort_buffer_size是为每个排序线程分配的缓冲区大小,增加该值可以加快ORDER BY与GROUP BY操作。
  • 增加 read_rnd_buffer_size
    当按照排序后的顺序读取行时,通过该缓冲区读取行,从而避免搜索硬盘。将该变量设置为较大值,可以大大改进ORDER BY的性能。

sort_buffer_size,read_rnd_buffer_size 只需要为运行大查询的客户端更改绘画变量即可。不应该修改全局变量。

(3)优化子查询

由于子查询可读性比较好,所以有些研发人员习惯于编写子查询,特别是刚接触数据库编程的新手。但子查询往往也是性能杀手,在生产环境中,子查询是最常见的导致性能问题的症结所在。
对于数据库来说,在绝大部分情况下,连接会比子查询更快。使用连接的方式,MySQL优化器一般可以生成更佳的执行计划,可以预先装载数据,更高效地处理数据查询。而子查询往往需要运行重复的查询,子查询生成的临时表也没有索引,因此效率会更低。

矮子里面找大个,大部分情况,子查询还不如连接查询呢。

(4)优化Limit

Web应用经常需要对查询的结果进行分页,分页算法offset一旦值很大,效率就会很差,因为MySQL必须检索大量的记录,然后丢弃大部分数据(offset+row_count)。
1)限制页数,只显示前几页,超过了一定页数之后,直接显示“更多more”,对于N页之后的结果,用户一般也不会关心。
2)要避免设置offset值,也就是避免丢弃数据。

-- 通过增加定位列 id > 1000 可以避免设置offset值
SELECT id,name,address,phone
FROM customer
WHERE id > 1000
ORDER BY id LIMIT 10;

也可以使用条件限制要排序的结果集:

WHERE date_time BETWEEN '2024-04-01 00:00:00' AND '2024-07-01 00:00:00' ORDER BY id;

(5) 优化IN列

对于IN列表,MySQL会排序IN列表里面的值,并使用二分查找法的方式定位数据。
但是把IN改成OR的形式并不能提高执行效率。建议IN中列值不超过200个,对于高并发的业务,小于几十条最佳。
如果能将其转化为多个等于的查询,那么这种方式最佳。

SELECT * FROM tableA WHERE id IN(SELECT id FROM tableB);

我们可以先查询(SELECT id FROM tableB),把获取到值逐个拼接,转化为SELECT * FROM tableA WHERE id = ?的形式,这个操作用程序实现很容易。

(6)优化Union

UNION语句默认是移出重复记录,结果集很大,还要全表扫描再去重,成本会很高。所以尽量使用UNION ALL语句。对于多个UNION数据库分表的时候,就应该保证数据是唯一的,这样就无需UNION去重。
另外,查询语句外层的WHERE并不会应用到每个单独的UNION,应该在每个UNION字句中添加上WHERE条件。

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

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

相关文章

【鸿蒙开发】鸿蒙ArkUI自定义组件如何封装一个好用的Toast/Loading/ProgressHUD组件

1. HUD 在移动端 App 开发中,Toast 、 Loading 和 Progress 是十分常用的UI控件,如果不做特殊要求,一般可以直接使用系统 API 提供的方法,但如果想要定制化 UI,就需要自定义实现了。 在 HarmonyOS 中,Toa…

Leetcode—769. 最多能完成排序的块【中等】

2024每日刷题&#xff08;149&#xff09; Leetcode—769. 最多能完成排序的块 实现代码 class Solution { public:int maxChunksToSorted(vector<int>& arr) {int ans 0;int mx INT_MIN;for(int i 0; i < arr.size(); i) {mx max(arr[i], mx);if(mx i) {a…

单GPU训练一天,Transformer在100位数字加法上就达能到99%准确率

乘法和排序也有效。 自 2017 年被提出以来&#xff0c;Transformer 已成为 AI 大模型的主流架构&#xff0c;一直稳站 C 位。 但所有研究者都不得不承认的是&#xff0c;Transformer 在算数任务中表现非常糟糕&#xff0c;尤其是加法&#xff0c;这一缺陷在很大程度上源于 Tra…

python毕业设计选题求职招聘系统-可视化大屏

✌网站介绍&#xff1a;✌10年项目辅导经验、专注于计算机技术领域学生项目实战辅导。 ✌服务范围&#xff1a;Java(SpringBoo/SSM)、Python、PHP、Nodejs、爬虫、数据可视化、小程序、安卓app、大数据等设计与开发。 ✌服务内容&#xff1a;免费功能设计、免费提供开题答辩P…

虚拟机配置RabbitMQ集群教程

RabbitMQ是常用的一款消息中间件&#xff0c;那么如何在我们虚拟机中创建其集群呢&#xff1f;跟着博主这篇文章让你一步到位 本篇搭建的是三台机器为一个集群&#xff01;假设大家虚拟机都为初始化状态&#xff0c;从0开始&#xff08;注意集群搭建需要CentOS8以上环境&#x…

Linux:基础

一、安装 二、 一些组件 2.1 git管理 集中式版本控制系统:版本库是集中存放在中央服务器的,需要时要先从中央服务器取得最新的版本进行修改,修改后再推送给中央服务器。集中式版本控制系统最大的毛病就是必须联网才能工作,网速慢的话影响太大。 分布式版本控制系统:分布…

Redis的使用场景——热点数据缓存

热点数据缓存 Redis的使用场景——热点数据的缓存 1.1 什么是缓存 为了把一些经常访问的数据&#xff0c;放入缓存中以减少对数据库的访问效率&#xff0c;从而减少数据库的压力&#xff0c;提高程序的性能。【在内存中存储】 1.2 缓存的原理 查询缓存中是否存在对应的数据如…

学习记录day19——数据结构 查找算法

概念 在给定数据元素的某个值&#xff0c;在查找表中确定一个其关键字等于给定值的数据元素的操作&#xff0c;叫做查找 查找的分类 顺序查找:将待查找数据&#xff0c;进行全部遍历一遍&#xff0c;直到找到要查找的元素 折半查找:每次都去除一半的查找范围的查找方式&#x…

Easy es问题总结

官网教程&#xff1a;https://www.easy-es.cn/pages/ac41f0/#settings 一 测试项目 1 pom <dependencies><!-- 排除springboot中内置的es依赖,以防和easy-es中的依赖冲突--><dependency><groupId>org.springframework.boot</groupId><artifa…

JavaScript 将网址 www. 抹去

简单好用 https://andi.cn/page/621609.html

【OpenCV C++20 学习笔记】序列化——XML和YAML文件处理

序列化——XML和YAML文件处理 序列化和反序列化代码实现XML/YAML文件的打开和关闭写入或读取文本和数字写入或读取OpenCV数据写入或读取数组以及map读取和写入自定义数据类型 输出结果 序列化和反序列化 如果希望永久保存某些对象&#xff0c;而不是每次运行程序的时候重新创建…

3DGS如何重塑点云配准?港中大开源首例3DGS配准工作!

论文标题&#xff1a; GaussReg: Fast 3D Registration with Gaussian Splatting 论文作者&#xff1a; Jiahao Chang, Yinglin Xu, Yihao Li, Yuantao Chen, and Xiaoguang Han 开源地址&#xff1a;https://jiahao620.github.io/gaussreg 导读&#xff1a; 点云配准是实现…

JavaScript(15)——操作表单元素属性和自定义属性

操作表单元素属性 表单很多情况&#xff0c;也需要修改属性&#xff0c;比如点击眼睛可以看到密码&#xff0c;本质是把表单类型转换为文本框正常的有属性有取值的&#xff0c;跟其他的标签属性没有任何区别 获取&#xff1a;DOM对象.属性名 设置&#xff1a;DOM对象.属性名…

国产超低功耗、±0.5℃精度的数字温度传感芯片 - M601B

温度传感芯片感温原理基于CMOS半导体PN节温度与带隙电压的特性关系&#xff0c;经过小信号放大、模数转换、数字校准补偿后&#xff0c;数字总线输出&#xff0c;具有精度高、一致性好、测温快、功耗低、可编程配置灵活、寿命长等优点。 数字温度传感芯片 - M601B&#xff0c;该…

如何解决 Nginx 与自动驾驶系统的集成问题?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01; 文章目录 如何解决 Nginx 与自动驾驶系统的集成问题&#xff1f; 如何解决 Nginx 与自动驾驶系统的集成问题&#xff1f; 在当今科技飞速发展的时代&#xff0c;自动驾驶…

【基础算法总结】队列 + 宽搜(BFS)

队列 宽搜BFS 1.N 叉树的层序遍历2.二叉树的锯齿形层序遍历3.二叉树最大宽度4.在每个树行中找最大值 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#…

配置web服务器练习

4练习要求&#xff1a; 练习一&#xff1a;配置web服务器&#xff0c;当访问网站 www.haha.com 时显示&#xff1a;haha 练习二&#xff1a;配置web服务器&#xff0c;当访问网站 www.xixi.com/secret/ 时显示&#xff1a;this is secret 具体步骤&#xff1a; 1、配置yum…

go程序在windows服务中优雅开启和关闭

本篇主要是讲述一个go程序&#xff0c;如何在windows服务中优雅开启和关闭&#xff0c;废话不多说&#xff0c;开搞&#xff01;&#xff01;&#xff01;   使用方式&#xff1a;go程序 net服务启动 Ⅰ 开篇不利 Windows go进程编译后&#xff0c;为一个.exe文件,直接执行即…

docker挂载部署reids6.2.1

1.拉取镜像 docker pull redis:6.2.12.创建挂在目录&#xff08;根据自己要求修改具体目录&#xff09; mkdir -p /home/admin/redis/{data,conf}3.在/home/admin/redis/conf目录下创建redis.conf文件 cd /home/admin/redis/conf touch redis.conf4.复制下面文本到redis.conf…