前言:说到mysql调优 我们第一反应都是想到索引调优 应该这是最基本的 也是至关重要的;一般工作个两年 索引调优都可以掌握的八九不离十,相关数据结构特点也都能说个一二出来,所以本文重点是讲述其它机制
整体架构
连接器:管理连接,客户端发起请求,连接到MySQL服务器。
缓存:检查是否有相同的查询结果缓存;没有缓存则继续执行,有缓存则直接返回。
MySQL 8.0移除查询缓存的原因
锁竞争问题:
查询缓存在高并发环境下会导致大量的锁竞争。
因为查询缓存需要在查询开始时进行检查,
在查询结束后进行更新,这会引发锁争用,
反而降低系统性能。
效果有限:
查询缓存仅对特定的、重复的查询有效,
而现代应用的查询往往是动态生成的,
命中率较低,因此实际效果有限。
分析器:解析SQL语句,分析是否有语法错误等,所有SQL语句都经过解析。
优化器:优化器决定如何执行操作,选择最佳的执行顺序和索引。
执行器:执行器根据优化计划执行查询, 调用存储引擎接口
存储引擎: 执行器通过存储引擎获取数据,数据可能已经缓存到Buffer Pool中,否则需要从磁盘加载。
buffer pool:
InnoDB存储引擎使用的内存区域,
用于缓存行数据和索引。
它可以极大地减少磁盘I/O操作,
因为频繁访问的数据会保存在内存中,
而不需要每次都从磁盘读取。
慢查询分析
通过mysql的架构组成,我们可以分析出,慢查询主要原因可能出现在
-
连接器
连接数过小,举个栗子 如果client和mysql之间只有一条长连接,那么第二条sql查询需要等待第一条的结果返回。很可能出现的一种表现形式就是,程序日志显示sql执行了数分钟,但是mysql查询语句本身并没有什么问题 这就可能刚好程序执行时 连接数占满了。
连接数由mysql端和client端配置共同决定,由于mysql默认的连接数大多场景够用 所以大部分我们只接触到配置client端连接数,如果都到了性能瓶颈的程度,那么mysql侧的连接数配置不能忽视。
mysql服务端连接数默认为100,最大可达16384,可以通过以下命令修改
(在my.inf修改也是可以的):mysql> set global max_connection=100;
my.ini / my.inf 配置示例
client端配置:比如python中django中的配置
# 本项目使用的是 django-db-connection-pool 连接池,另外python还有DBUtils(可以支持各种数据库)等连接池可选用 # show PROCESSLIST; show status like '%connect%'; 可通过这两组命令验证连接池是否生效 'POOL_OPTIONS': { 'POOL_SIZE': 20, # 最小 'MAX_OVERFLOW': 20, # 在最小的基础上,还可以增加20个,即:最大40个。 'RECYCLE': 24 * 60 * 60, # 连接可以被重复用多久,超过会重新创建,-1表示永久。 'TIMEOUT': 30, # 池中没有连接最多等待的时间。 }
java中的druid连接池
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver #driver-class-name: org.postgresql.Driver #driver-class-name: oracle.jdbc.OracleDriver #driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver #driver-class-name: dm.jdbc.driver.DmDriver druid: initial-size: 5 max-active: 20 min-idle: 5 max-wait: 60000
简而言之 mysql连接数决定上限,client端连接决定下限。
-
优化器
优化器选错了索引执行,我们常说的索引失效或者未命中索引 也是因为优化器没能正确选择索引导致的,可以通过explain排查,至于产生原因 大家在八股文想必也看腻了 ,但不得不提醒 这部分才是重点 工作中99%调优都在索引调优层面, 本文不再重复。
索引文章可以在博主(csdn:孟秋与你)主页搜索:mysql索引
-
存储引擎
主要是针对Buffer Pool , 索引和行数据会存放在Buffer Pool中,作为一个缓冲池 它也是有大小的,如果Buffer Pool的内存被耗尽 那自然也会影响存放。可以通过以下命令查看Buffer Pool的命中率:
mysql>SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';
或看更多信息
mysql>SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_%';
Innodb_buffer_pool_read_requests : 读请求次数
Innodb_buffer_pool_reads: 从磁盘读取的次数
命中率计算:
Buffer Pool Hit Rate = (Innodb_buffer_pool_read_requests - Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests一般命中率低于99%时,才考虑调整大小
tips: buffer pool 根据LRU算法进行内存淘汰,比如将一些访问频率相对低的旧数据剔除。
(不考虑mysql8移除的缓存因素,注意 缓存不是指buffer pool)