高性能 MySQL(八):通过优化数据访问,来解决慢查询

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 前面几篇文章中介绍了如何设计最优的库表结构,以及如何建立最好的索引,这些对于高性能来说是必不可少的。但这还不够——还需要合理的设计查询。如果查询写得很糟糕,即使库表结构再合理、索引再合适,也无法实现高性能。

572f78222f941355a191d47a6fcc5734_image_auth_key=1686638014-bgmCV8o5kVmA99igPURgLH-0-54cf62ae8f13811b10adbfed9c848415&file_size=58402.png

大家好,我是水滴~~

前面几篇文章中介绍了如何设计最优的库表结构,以及如何建立最好的索引,这些对于高性能来说是必不可少的。但这还不够——还需要合理的设计查询。如果查询写得很糟糕,即使库表结构再合理、索引再合适,也无法实现高性能。


一、为什么查询速度会慢

如果把查询看作是一个任务,那么它由一系列子任务组件,每个子任务都会消耗一定的时间。如果想要优化查询,实际上要优化其子任务,要么消除其中一些子任务,要么减少子任务的执行次数,要么让子任务运行得更快。

通常来说,一个查询的生命周期,按顺序大致分为:从客户端,到服务端,然后在在服务器上进行解析,生成执行计划,执行,并返回结果给客户端。其中“执行”可以认为是整个生命周期中最重要的阶段,这其中包括大量为了检索数据,而到存储引擎的调用,以及调用后的数据处理,包括排序、分组等。

在完成这些任务的时候,查询需要在不同的地方花费时间,包括网络,CPU 计算,生成统计信息和执行计划、锁等待(互斥等待)等操作,尤其是向底层存储引擎检索数据的调用操作。

在每一个消费大量时间的查询案例中,我们都能看到一些不必要的额外操作、某些操作被重复了很多次、某些操作执行得太慢等。优化查询的目的就是减少和消除这些操作所花费的时间。

二、优化数据访问

查询性能低下最基本的原因是访问的数据太多。大部分性能低下的查询都可以通过减少访问的数据量的方式进行优化。对于低效的查询,可以通过下面两个步骤来分析。

1. 是否向数据库请求了不需要的数据

有些查询会请求超过实际需要的数据,然后这些多余的数据会被应用程序丢弃。这会给 MySQL 服务器带来额外的负担,并增加网络开销,另外也会消耗应用服务器的 CPU 和内存资源。

下面列出一些典型的案例:

1.1 查询不需要的记录

一个常见的案例是,当需要获取最新一条数据时,一些开发者会按时间倒序查询出所有数据,并返回给应用程序,然后应用程序再获取结果集中的第一条。

select * from student order by create_time desc;

最简单有效的解决方法是,在查询后面加上 LIMIT

select * from student order by create_time desc limit 1;

1.2 多表关联时返回全部列

比如我们要查出所有“软件工程2101班”的所有学生,下面写法是不推荐的:

SELECT
  * 
FROM
  student s
  INNER JOIN class c ON s.class_id = c.id 
WHERE
  c.NAME = '软件工程2101班';

该查询会返回这两个表的全部数据列。正确的方式应该像下面这样,只取需要的列:

SELECT
  s.* 
FROM
  student s
  INNER JOIN class c ON s.class_id = c.id 
WHERE
  c.NAME = '软件工程2101班';

1.3 总是取出全部列

每次看到select *的时候都需要用怀疑的眼光审视,是不是真的需要返回全部的列?很可能不是必需的。

取出全部的列,会让优化器无法完成索引覆盖扫描这类优化,还会为服务器带来额外的 I/O、内存和 CPU 的消耗。

当然,使用select *也并不总是坏事。在很多案例当中,这种方式能够提高相同代码片段的复用性,简化了开发。如果能够清楚这样做的性能影响,也是值得考虑的。

1.4 重复查询相同的数据

在一些情况下,需要不断地重复执行相同的查询,然后每次返回完全相同的数据。例如,在用户评论的地方需要查询用户头像的 URL,那么用户多次评论的时候,可能就会反复查询这个数据。像这种应用场景,一般通过缓存技术来避免重复查询相同的数据。

2. MySQL 是否在扫描额外的记录

在确定查询只返回需要的数据以后,接下来应该看看 MySQL 为了返回结果,是否扫描了过多的数据。对于 MySQL,最简单的衡量查询开销的三个指标如下:

2.1 响应时间

响应时间是两个部分之和:服务时间和排队时间。

  • 服务时间是指数据库处理这个查询真正花了多长时间。
  • 排队时间是指服务器因为等待某些资源而没有真正执行查询的时间(例如等待 I/O 操作完成、等待行锁等等)

当我们看到一个查询的响应时间的时候,首先需要问问自己,这个响应时间是否是一个合理的值。

2.2 扫描的行数和返回的行数

分析查询时,查看该查询扫描的行数是非常有帮助的。这在一定程度上能够说明查询的效率高不高。

较短的行的访问速度更快,内存中的行也比磁盘中的行的访问速度要快得多。

理想情况下,扫描的行数和返回的行数应该是相同的。但实际情况中这种“美事”并不多。

2.3 扫描的行数和访问类型

在评估查询开销的时候,需要考虑一下从表中找到某一行数据的成本。MySQL 有好几种访问方式可以查找并返回一行结果。有些访问方式可能需要扫描多行才能返回一行结果,也有些访问方式可能无需扫描就能返回结果。

EXPLAIN语句中的type列反应了访问类型。访问类型有很多种:全表扫描、索引扫描、范围扫描、唯一索引查询、常数引用等。刚才列出的类型,速度是从慢到快,扫描的行数也是从小到大。

如果查询没有办法找到合适的访问类型,那么解决的最好办法通常就是增加一个合适的索引。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
25天前
|
安全 关系型数据库 MySQL
如何将数据从MySQL同步到其他系统
【10月更文挑战第17天】如何将数据从MySQL同步到其他系统
140 0
|
7天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
113 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
7天前
|
SQL 关系型数据库 MySQL
MySQL慢查询优化、索引优化、以及表等优化详解
本文详细介绍了MySQL优化方案,包括索引优化、SQL慢查询优化和数据库表优化,帮助提升数据库性能。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
MySQL慢查询优化、索引优化、以及表等优化详解
|
7天前
|
缓存 NoSQL 关系型数据库
Redis和Mysql如何保证数据⼀致?
在项目中,为了解决Redis与Mysql的数据一致性问题,我们采用了多种策略:对于低一致性要求的数据,不做特别处理;时效性数据通过设置缓存过期时间来减少不一致风险;高一致性但时效性要求不高的数据,利用MQ异步同步确保最终一致性;而对一致性和时效性都有高要求的数据,则采用分布式事务(如Seata TCC模式)来保障。
39 14
|
10天前
|
SQL 前端开发 关系型数据库
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
39 9
|
11天前
|
缓存 监控 关系型数据库
如何优化MySQL查询速度?
如何优化MySQL查询速度?【10月更文挑战第31天】
37 3
|
14天前
|
缓存 关系型数据库 MySQL
如何优化 MySQL 数据库的性能?
【10月更文挑战第28天】
37 1
|
21天前
|
NoSQL 关系型数据库 MySQL
MySQL与Redis协同作战:百万级数据统计优化实践
【10月更文挑战第21天】 在处理大规模数据集时,传统的单体数据库解决方案往往力不从心。MySQL和Redis的组合提供了一种高效的解决方案,通过将数据库操作与高速缓存相结合,可以显著提升数据处理的性能。本文将分享一次实际的优化案例,探讨如何利用MySQL和Redis共同实现百万级数据统计的优化。
54 9
|
15天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
77 1
|
21天前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。