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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 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
相关文章
|
10天前
|
关系型数据库 MySQL 数据库
ORM对mysql数据库中数据进行操作报错解决
ORM对mysql数据库中数据进行操作报错解决
34 2
|
10天前
|
SQL 关系型数据库 MySQL
MySQL如何排查和删除重复数据
该文章介绍了在MySQL中如何排查和删除重复数据的方法,包括通过组合字段生成唯一标识符以及使用子查询和聚合函数来定位并删除重复记录的具体步骤。
29 2
|
1月前
|
canal 消息中间件 关系型数据库
Canal作为一款高效、可靠的数据同步工具,凭借其基于MySQL binlog的增量同步机制,在数据同步领域展现了强大的应用价值
【9月更文挑战第1天】Canal作为一款高效、可靠的数据同步工具,凭借其基于MySQL binlog的增量同步机制,在数据同步领域展现了强大的应用价值
207 4
|
5天前
|
消息中间件 canal 关系型数据库
Maxwell:binlog 解析器,轻松同步 MySQL 数据
Maxwell:binlog 解析器,轻松同步 MySQL 数据
38 11
|
21天前
|
SQL 缓存 关系型数据库
MySQL高级篇——关联查询和子查询优化
左外连接:优先右表创建索引,连接字段类型要一致、内连接:驱动表由数据量和索引决定、 join语句原理、子查询优化:拆开查询或优化成连接查询
MySQL高级篇——关联查询和子查询优化
|
21天前
|
算法 关系型数据库 MySQL
MySQL高级篇——排序、分组、分页优化
排序优化建议、案例验证、范围查询时索引字段选择、filesort调优、双路排序和单路排序、分组优化、带排序的深分页优化
MySQL高级篇——排序、分组、分页优化
|
3天前
|
关系型数据库 MySQL 数据库
MySQL的语法涵盖了数据定义、数据操作、数据查询和数据控制等多个方面
MySQL的语法涵盖了数据定义、数据操作、数据查询和数据控制等多个方面
17 5
|
5天前
|
存储 关系型数据库 MySQL
MySQL索引失效及避免策略:优化查询性能的关键
MySQL索引失效及避免策略:优化查询性能的关键
22 3
|
5天前
|
缓存 关系型数据库 MySQL
MySQL数据库优化:提升性能和扩展性的关键技巧
MySQL数据库优化:提升性能和扩展性的关键技巧
14 2
|
10天前
|
关系型数据库 MySQL 数据库
Python MySQL查询返回字典类型数据的方法
通过使用 `mysql-connector-python`库并选择 `MySQLCursorDict`作为游标类型,您可以轻松地将MySQL查询结果以字典类型返回。这种方式提高了代码的可读性,使得数据操作更加直观和方便。上述步骤和示例代码展示了如何实现这一功能,希望对您的项目开发有所帮助。
34 4
下一篇
无影云桌面