欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > MySQL 调优:查询慢除了索引还能因为什么?

MySQL 调优:查询慢除了索引还能因为什么?

2025/3/26 2:09:19 来源:https://blog.csdn.net/qq_45693006/article/details/146442121  浏览:    关键词:MySQL 调优:查询慢除了索引还能因为什么?

文章目录

    • 情况一:连接数过小
    • 情况二:Buffer Pool 太小

MySQL 查询慢除了索引还能因为什么?MySQL 查询慢,我们一般也会想到是因为索引,但除了索引还有哪些原因会导致数据库查询变慢呢?

以下以 MySQL 中一条 SQL 的执行流程为基础,分析 MySQL 查询慢除了索引还有哪些原因。

当 MySQL 中一条查询 SQL 在实际进入影响 SQL 执行效率的流程前(主要是优化器流程与执行器流程),首先会进入分析器流程。以 Python 进程为例,以下举例一条 MySQL 语句执行下来会经历哪些流程。

例如在 MySQL 中有一张名为 use_info 的数据表,一个 Python 进程尝试携带账号密码等信息尝试向 MySQL 建立一条网络连接,而 MySQL 的连接管理模块会对这条连接进行管理。

在连接被建立后,Python 应用尝试向 MySQL 服务器执行如下 SQL 查询语句:

SELECT user_name,user_address FROM user_info where user_id = 1;

此时 Python 进程需要将 SQL 语句通过网络连接给 MySQL,MySQL 收到 SQL 语句后将在分析器中先判断一下 SQL 语句有没有语法错误。例如 SELECT 是否少写个 L:

SEECT user_name,user_address FROM user_info where user_id = 1;

如果 SQL 错误,SELECT 中确实少写个 L,将抛出相关的异常提示:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SEECT user_name,user_address FROM user_info where user_id = 1' at line 1

SQL 在分析器过程中执行无误后将到达优化器,而优化器会根据一些规则选择需要使用的索引,之后执行器会调用存储引擎的接口函数,MySQL 中的存储引擎是MySQL 中真正负责读写数据的组件。在如今的 MySQL 数据库开发中,最常用的存储引擎就是 InnoDB 存储引擎。

由于读写磁盘较慢,所以 InnoDB 存储引擎内部增加了一层名为 Buffer Pool 的内存提速设计, 在 Buffer Pool 中即存放行数据又存放索引数据。查询 SQL 到了 InnoDB 中会根据前面优化器里计算得到的索引去查询相应的索引页,如果索引页不在 Buffer Pool 里,则从磁盘里加载到索引页,再通过索引页查询得到数据页的位置。如果这些数据页不在 Buffer Pool 中,则从磁盘里加载进来,最后将得到的一行行数据结果返回给客户端。

在优化器流程与执行器流程过程中,数据库慢查询一般是优化器选错索引导致。这类问题可以通过 EXPLAIN 命令排查。

但是,除了索引之外,还有哪些因素会限制查询速度呢?

情况一:连接数过小

MySQL 的连接管理模块作用是管理客户端和 MySQL 之间的长连接,假设两者之间只有一条连接,那么在执行 SQL 查询之后只能阻塞等待结果返回,如果有大量查询同时并发请求,那么后面的请求都需要等待前面的请求执行完成后才能开始执行。因此有时候从应用程序的日志看,有些 SQL 执行了几分钟,但将 SQL 单独拎出来执行却只有几毫秒的情况。对于这种情况,实际上就是因为这些 SQL 语句在等待前面的 SQL 执行完成。

那么这个问题该如何解决呢?其实多建立一些连接就可以解决这个问题,多建一些连接目的是让请求能够并发执行,从而使后面的连接不需要等待那么久。但需要注意的是,连接数过小的问题受数据库和客户端两侧同时限制。

  • 数据库连接数过小的情况:

    MySQL 的最大连接数默认是100,最大可以达到 16384,可以通过如下命令将 SQL 的最大连接数改为500。

    SET GLOBAL max_connections = 500;
    

    查看 MySQL 最大连接数配置命令:

    SHOW GLOBAL VARIABLES LIKE 'max_connections';
    
  • 应用侧连接数过小的情况:

    如果数据库连接大小是调整过了,但却没啥效果,那可能是因为服务应用(如 Java 或 Python 应用等)的连接数也过小。应用侧与 MySQL 底层的连接是基于 TCP 协议的长连接,而建立长连接比较耗时,所以通常情况下会维护一个长连接池,要执行 SQL 时从里面捞出一条连接出来用,用完塞回去,下次复用。

    需要注意的是,连接池的容量会有上限,连接池容量的上限指的是连接池能够控制的连接数量,如果连接池容量的上限太低,那么修改连接池最大连接数也没什么作用。

    如果需要调大这个连接池该如何调呢?在实际编码中,通常服务应用(如 Java 或 Python 应用等)都会通过 ORM 库进行读写操作,而成熟的 ORM 库会有个连接池的配置,按照官方文档改就好。

情况二:Buffer Pool 太小

Buffer Pool 太小也会导致 MySQL 查询慢的问题。在前文提到的 InnoDB 存储引擎中里有一层内存 Buffer Pool,Buffer Pool 通过缓存磁盘数据用于加速查询,如果 Buffer Pool 越大,那么 Buffer Pool 中能够存放的数据页就越多,相应的 SQL 查询时就更可能命中 Buffer Pool,那么 MySQL 查询速度自然更快。

可以执行下面命令增大 Buffer Pool 的大小:

SET GLOBAL innodb_buffer_pool_size = 536870912;

innodb_buffer_pool_size 是 MySQL 中用于设置 Buffer Pool 的参数,它的单位为字节。上例中,将 innodb_buffer_pool_size 的值设置为 536870912 即将将 InnoDB 缓冲池的大小为 536870912 字节,换算成兆字节(MB)为 521 MB(因为 1 MB = 1024 * 1024 个字节)。

查询 innodb_buffer_pool_size 的大小命令:

SHOW GLOBAL VARIABLES LIKE 'innodb_buffer_pool_size';

输出的结果例如:

在这里插入图片描述

但是如果数据库查询慢并不是由于 Buffer Pool 的大小导致,那么修改 Buffer Pool 的大小就毫无意义。那么如何判断 Buffer Pool 是不是太小了?可以通过查看 Buffer Pool 的命中率来分析。

可以通过如下命令查询 Buffer Pool 的一些相关信息:

SHOW STATUS LIKE 'Innodb_buffer_pool_%';

得到的 Buffer Pool 相关信息例如:

在这里插入图片描述

其中 Innodb_buffer_pool_read_requests 表示请求的次数,Innodb_buffer_pool_reads 表示从物理磁盘中读数据的请求次数。

Buffer Pool 的命中率可以通过如下公式计算:

1-(Innodb_buffer_pool_reads/Innodb_buffer_pool_read_requests)*100%

例如上述 Buffer Pool 的命中率为:

1-(68759212/4966742025)*100% ≈ 98.6156%

一般情况下,Buffer Pool 的命中率都在 99% 以上,如果低于 99% 才需要考虑加大 Buffer Pool 的大小。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词