Mysql从入门到入神之(六)查询性能优化

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 前言文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820…种一棵树最好的时间是十年前,其次是现在

絮叨


我们继续来探索mysql。前面我们了解了mysql的索引的一些基础知识,今天我们来康康B+树索引

上面那章是基础,讲的是单表的查询方式,如果没有看过的,请移驾上面一章。


慢查询基础:优化数据访问



查询性能低下的很大的原因就是我们要查询的数据太多,你一个报表查询本来就得很慢,对于低效的查询,我们可能参考以下2个步骤。

  • 确定应用程序是否在检索大量超过需要的数据。
  • 确定mysql 服务器层是否分析大量超过需要的数据。


是否像数据库请求了不需要的数据。

有很多sql,请求了超过实际需要的数据,这种会给服务器带来额外的负担,并增加网络开销。比如下面的案例就是不好的案例

  • 例如只需要返回2个列 但是你却使用了*这种情况就是不应该的。
  • 第二个就是你比如需要查询10条数据,但是你确没有用limit去限制查询的个数。


是否扫描额外的记录

在确定以及肯定我们需要返回的行数之后,接下来需要优化的就是看是否查询了过多的数据,对于mysql来说,最简单的衡量查询开销的三个指标如下:

  • 响应时间
  • 扫描行数
  • 返回的行数


扫描行数和返回行数

如果发现我们扫描过多的行数,但是我们确只是返回少量的行数,这种的优化方式有以下几个方面。

  • 使用索引覆盖扫描,把所有需要的列都放到索引中,这样存储引擎无须回表获取对应行就可以返回结果了
  • 改变库表结构,使用单独的汇总表
  • 重写这个复杂的sql,用代码的逻辑来拆分这个sql。


重构查询方式


在优化查询问题时,我们的目标是找到一个方法,只要结果是和原来的结果相同,然后更少的时间开销的方法,以前总是强调需要数据库层面去完成尽可能多的工作,这样的逻辑在以前认为成立的原因是他们以为网络开销会很高,但是这些对于mysql来说并不适用,mysql的连接和断开都是很轻量的,所以小查询才是王道


一个复杂的查询还是多个简单的查询

我最近接手一个项目,前同事的sql里面全是逻辑。导致系统的性能特别的慢,然后我们接手之后,做了一波优化,把他全部拆成多个简单的查询,虽然说连接的次数多了,但是我们的查询效率,和代码的可复用性,可拓展性不知道强了多少倍,所以说看情况,如果可以优化成多个简单查询,就尽量优化。


切分查询 (分而治之)

就拿批量更新来说,比如我修改了一个题目的章节,我需要修改这个题目以前做个的用户的章节,那么我就需要批量更新,如果说一次性更新那么多的数据,是不是会锁很多的数据,导致大事务,如果我把他拆成多个更新,每次更新1k个就会好很多。


分解关联查询

很多高性能的应用都会对关联查询进行分解,简单地,可以对每一张表进行单表查询,然后把查出来的结果在应用层去做关联,比如下面的例子

我们其实是可以分解成下面的sql

为啥要这样做。这样做的好处是什么

  • 拆分查询之后,执行单个查询 可以减少锁竞争
  • 在应用层做分解,更加容易对数据库进行拆分,更容易做到高性能的拓展
  • 查询本身的性能也会有所增加
  • 拆分查询可以减少冗余的查询


关联子查询优化

其实很多的关联子查询是非常糟糕的,最糟的是 where 后面跟 in的子查询,一般像这样的子查询我们建议使用left join来实现


对最大值,最小值的优化,

很多情况下,对一个字段求他的最大值,最小值,我们会用函数去做,但是这样的情况并不是最好的,比如有些场景,就是我们可以知道这个查询字段如果是索引的话,那么索引本身就是有排序的,那么我们只需要把他排序好,取limit 1 比你用 函数会好很多。


对count的优化

很多博客啥的说最后不要count(),其实他们这样是错误的,其实最好的查询结果的行数的方式就是count(),因为人家底层对他做了优化的。

按照效率排序的话,count(字段)<count(主键 id)<count(1)≈count(),所以我 建议你,尽量使用 count()。


连接的原理


搞数据库一个避不开的概念就是Join,翻译成中文就是连接。相信很多小伙伴在初学连接的时候有些一脸懵逼,理解了连接的语义之后又可能不明白各个表中的记录到底是怎么连起来的,以至于在使用的时候常常陷入下边两种误区:

  • 误区一:业务至上,管他三七二十一,再复杂的查询也用在一个连接语句中搞定。
  • 误区二:敬而远之,上次 DBA 那给报过来的慢查询就是因为使用了连接导致的,以后再也不敢用了。


内连接和外连接的概念

  • 对于内连接的两个表,驱动表中的记录在被驱动表中找不到匹配的记录,该记录不会加入到最后的结果集,我们上边提到的连接都是所谓的内连接。
  • 对于外连接的两个表,驱动表中的记录即使在被驱动表中没有匹配的记录,也仍然需要加入到结果集。
  • 在MySQL中,根据选取驱动表的不同,外连接仍然可以细分为2种: - 左连接 - 右连接

可是这样仍然存在问题,即使对于外连接来说,有时候我们也并不想把驱动表的全部记录都加入到最后的结果集。这就犯难了,有时候匹配失败要加入结果集,有时候又不要加入结果集,这咋办,有点儿愁啊。。。噫,把过滤条件分为两种不就解决了这个问题了么,所以放在不同地方的过滤条件是有不同语义的:

  • WHERE子句中的过滤条件
  • WHERE子句中的过滤条件就是我们平时见的那种,不论是内连接还是外连接,凡是不符合WHERE子句中的过滤条件的记录都不会被加入最后的结果集。
  • ON子句中的过滤条件
  • 对于外连接的驱动表的记录来说,如果无法在被驱动表中找到匹配ON子句中的过滤条件的记录,那么该记录仍然会被加入到结果集中,对应的被驱动表记录的各个字段使用NULL值填充。


连接的原理


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

我们前边说过,对于两表连接来说,驱动表只会被访问一遍,但被驱动表却要被访问到好多遍,具体访问几遍取决于对驱动表执行单表查询后的结果集中的记录条数。对于内连接来说,选取哪个表为驱动表都没关系,而外连接的驱动表是固定的,也就是说左(外)连接的驱动表就是左边的那个表,右(外)连接的驱动表就是右边的那个表。我们上边已经大致介绍过t1表和t2表执行内连接查询的大致过程,我们温习一下:

  • 步骤1:选取驱动表,使用与驱动表相关的过滤条件,选取代价最低的单表访问方法来执行对驱动表的单表查询。
  • 步骤2:对上一步骤中查询驱动表得到的结果集中每一条记录,都分别到被驱动表中查找匹配的记录。


如果有3个表进行连接的话,那么步骤2中得到的结果集就像是新的驱动表,然后第三个表就成为了被驱动表,重复上边过程,也就是步骤2中得到的结果集中的每一条记录都需要到t3表中找一找有没有匹配的记录,用伪代码表示一下这个过程就是这样:

for each row in t1 {   #此处表示遍历满足对t1单表查询结果集中的每一条记录
    for each row in t2 {   #此处表示对于某条t1表的记录来说,遍历满足对t2单表查询结果集中的每一条记录
        for each row in t3 {   #此处表示对于某条t1和t2表的记录组合来说,对t3表进行单表查询
            if row satisfies join conditions, send to client
        }
    }
}
复制代码


使用索引加快连接速度

比如说在被驱动表上建立索引,让他们的查询类型变成 cast 或者是ref 这样就能加快查询速度了


基于块的嵌套循环连接(Block Nested-Loop Join)

提前划出一块内存(join buffer)存储驱动表结果集中的记录,然后开始扫描被驱动表,每一条被驱动表的记录一次性和这块内存中的多条驱动表记录匹配,可以显著减少被驱动表的I/O操作。

结尾


我们下章继续再战。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
8天前
|
缓存 关系型数据库 MySQL
MySQL索引策略与查询性能调优实战
在实际应用中,需要根据具体的业务需求和查询模式,综合运用索引策略和查询性能调优方法,不断地测试和优化,以提高MySQL数据库的查询性能。
|
13天前
|
存储 缓存 负载均衡
mysql的性能优化
在数据库设计中,应选择合适的存储引擎(如MyISAM或InnoDB)、字段类型(如char、varchar、tinyint),并遵循范式(1NF、2NF、3NF)。功能上,可以通过索引优化、缓存和分库分表来提升性能。架构上,采用主从复制、读写分离和负载均衡可进一步提高系统稳定性和扩展性。
32 9
|
16天前
|
SQL 前端开发 关系型数据库
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
46 9
|
17天前
|
缓存 监控 关系型数据库
如何优化MySQL查询速度?
如何优化MySQL查询速度?【10月更文挑战第31天】
44 3
|
23天前
|
SQL NoSQL 关系型数据库
2024Mysql And Redis基础与进阶操作系列(5)作者——LJS[含MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页等详解步骤及常见报错问题所对应的解决方法]
MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页、INSERT INTO SELECT / FROM查询结合精例等详解步骤及常见报错问题所对应的解决方法
|
21天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
104 1
|
27天前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。
|
24天前
|
SQL 关系型数据库 MySQL
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
43 1
|
22天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第26天】数据库作为现代应用系统的核心组件,其性能优化至关重要。本文主要探讨MySQL的索引策略与查询性能调优。通过合理创建索引(如B-Tree、复合索引)和优化查询语句(如使用EXPLAIN、优化分页查询),可以显著提升数据库的响应速度和稳定性。实践中还需定期审查慢查询日志,持续优化性能。
52 0
|
24天前
|
SQL 关系型数据库 MySQL
mysql编写sql脚本:要求表没有主键,但是想查询没有相同值的时候才进行插入
mysql编写sql脚本:要求表没有主键,但是想查询没有相同值的时候才进行插入
31 0