MySQL · 源码分析 · Query Cache内部剖析

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
简介: Query Cache背景Query Cache在其他数据库里面也称为结果集缓存。顾名思义,它的目的是将SELECT语句与其返回结果缓存到Query Cache中,如果重复执行相同的SELECT语句的话,我们可以跳过MySQL的解析、优化、执行阶段,将SELECT的查询结果直接返回到客户端,加速SELECT语句的执行。Query Cache中的主要数据结构Query_cache

Query Cache背景

Query Cache在其他数据库里面也称为结果集缓存。顾名思义,它的目的是将SELECT语句与其返回结果缓存到Query Cache中,如果重复执行相同的SELECT语句的话,我们可以跳过MySQL的解析、优化、执行阶段,将SELECT的查询结果直接返回到客户端,加速SELECT语句的执行。

Query Cache中的主要数据结构

Query_cache 对整个Query Cache进行管理,负责提供接口供Server调用。
Query_cache_block Query Cache中的所有存储都是以Query_cache_block来组织的。每一个Query_cache_block的格式都是Block_header + data.
Query_cache_table 用来记录单个数据表的Block_header。
Query_cache_block_table 用来存储与Query相关的数据表的Block_header。每一个数据表都有一个独立的Query_cache_block_table结构对应。与Query_cache_table的区别是,所有Query使用的同一个数据表对应同一个Query_cache_table。
Query_cache_query 用来记录Query的Block_header。
Query_cache_result 用来记录结果集的Block_header。
Query_cache_memory_bin 用来管理Query Cache的内存使用,Query Cache的整体内存被划分为多个bins。该结构在Query Cache初始化的过程中完成。请参考下面Query Cache内存初始化部分。
Query_cache_memory_bin_step 用来辅助初始化Query_cache_memory_bins,记录内存管理的每一层的bins内存分配的大小。请参考下面Query Cache内存初始化部分。
Query_cache_query_flags 用来记录影响Query返回结果的环境变量,比如sql_mode,字符集,time_zone等。

Query cache的存储结构

Query cache中是利用Query_cache_block对象进行存储的,存储结构如下图:

+----------------------------------------------------------------------------+
| Block header                                                               |
+----------------------------------------------------------------------------+
| Table of database table lists                                              |
+----------------------------------------------------------------------------+
| Type depended header                                                       |
+----------------------------------------------------------------------------+
| Data ...                                                                   |
+----------------------------------------------------------------------------+

说明

  • Block header:指的就是Query_cache_block这个结构体自身需要存储的一些信息。详细信息可以参考sql/sql_cache.h中的结构体说明。

  • Table of database table lists:这部分是用来记录与Query相关的所有数据表header信息(Query_cache_block_table结构)。对于一条Query来说,每个相关的数据表都有一个这样的header信息。而对于结果集数据块来说,这部分不包含数据。

  • Type depended header :这部分用来记录依赖于该Block的具体对象header,比如是Query_cache_query还是Query_cache_result。

  • Data:顾名思义,就是记录我们当前存储对象的数据信息。

Query cache的内存管理

Query cache依靠自己对内存进行管理。当用户调整query_cache_size系统参数时,Query cache会自动的修改内存大小。

Query cache内存的初始化

Query cache的内存初始化包含两个部分:

  1. 一次性申请query_cache_size大小的内存空间。

  2. 初始化内存管理方式。

Query cache的内存管理方式如下图所示:

内存管理模拟图

说明

Query cache对于整个内存的管理是将整个内存块划分多层大小不同的多个query_cache_memory_bins(简称bins)。具体的层数由query_cache_memory_bin_steps (简称steps)确定,steps是动态根据query_mem_size确定的,如何确定steps请参考Query_cache::init_cache。第N层的bins数量是由(前N-1层bins数量总和 + QUERY_CACHE_MEM_BIN_PARTS_INC) * QUERY_CACHE_MEM_BIN_PARTS_MUL 确定的。QUERY_CACHE_MEM_BIN_PARTS_INCQUERY_CACHE_MEM_BIN_PARTS_MUL是定义的控制每一层bins增量的两个宏。

Query cache内存的分配

Query cache刚初始化后,整个内存作为一个大的free_block。当需要申请新的数据块时,Query cache首先寻找大小最为接近的bins进行匹配,判断bins中有没有free_block。如果有则使用;如果没有则从其上一个bins中寻找free_block(bins是按照空间大小降序排列的,上层的bins大小要比下层的bins空间大),直到找到合适大小的一个。 如果最后没有找到合适大小的,Query cache将启动淘汰机制进行淘汰,以满足空间申请的需求。

Query cache内存的回收

在需要申请内存块时,如果没有找到合适大小的free block, Query cache将启动淘汰机制来淘汰最旧的缓存记录,释放的block将被分配到对于大小的bins中。如果分配过程中发现当前回收的free block和bins中free block地址相邻, 当前回收的free block将会和相邻的free block进行合并,重新插入到大小合适的bins中。另外Query cache通过flush query cache语句可以自动整理Query cache的defragments。

Query cache相关的几个重点系统变量

query_cache_type

范围 SESSION
类型 ENUM
功能 a) ON: cache所有SELECT语句。
b) OFF: 关闭query cache。(默认)。
c) DEMAND: 使用SQL_CACHE hint的SELECT语句才可以缓存

query_cache_size

范围 GLOBAL
类型 ULong
功能 a) 设置Query cache的大小,设置范围是(0 ~ ULONG_MAX)。
b) 默认值是1M。

query_cache_limit

范围 GLOBAL
类型 ULong
功能 a) 设置最大结果集大小范围,如果结果集超出了该值的大小,将不会被缓存。
设置范围是(0 ~ ULONG_MAX)。
b) 默认值是1M。

query_cache_min_res_unit

范围 GLOBAL
类型 ULong
功能 a) 设置内存申请的最小单元块的大小,如果设置太大会影响Query Cache的实际使用率,造成空间浪费。
如果设置太小会增加内存的分配以及合并成本。设置范围是(0 ~ ULONG_MAX)。
b) 默认值是4K。

Query cache相关的两个Hints

sql_no_cache

功能: 当前sql语句忽略使用query cache.

sql_cache

功能: 当query_cache_type为ON或者DEMAND时,考虑缓存当前sql语句的结果集。

Query cache的工作原理

为了快速查找,Query cache中维护着一个HASH map,用来记录Query对应的其所在的query_cache_block。其对应的Key由query + database + flag(包含影响执行结果的所有环境变量)组成。如果当前Query与任何Key比较一致的话,对应的结果集就可以被直接返回。

Query cache 的失效

当一个表发生改变时,所有与该表相关的cached queries将失效。一个表发生变化,包含多种语句,比如 INSERT, UPDATE, DELETE, TRUNCATE TABLE,ALTER TABLE, DROP TABLE, 或者 DROP DATABASE。
为了加速失效过程,Query cache中维护着一个HASH map, 用来记录table对应的query_cache_block_table。其Key由db_name + table_name构成。通过Key的比较可以获取query_cache_block_table,该对象包含一个双向链表,记录了所有与该表相关的cached queries。通过这样的方式便可以快速的失效一个表对应的所有cached queries。

Query cache 的监控

  • Query cache 通过show status可以看到如下一系列的状态信息:
Qcache_total_blocks Query cache总的块数。
Qcache_free_blocks Query cache的free blocks数。
Qcache_hits 通过Query cache,命中的query次数。
Qcache_inserts 该变量记录了之前有多少条query及其数据集成功插入了Query Cache中,即便插入的记录后来被淘汰了,该值也不会受到影响。
Qcache_lowmem_prunes Query cache中淘汰的query记录数。
Qcache_not_cached 未被缓存的query数。
Qcache_queries_in_cache 当前Query cache存在的query记录数,如果有记录被淘汰了,该值就会发生变化。注意与Qcache_inserts的不同。
Qcache_total_blocks 当前Query cache中总的blocks个数。
  • Optimizer_trace中会显示“query_result_read_from_cache:true”这样的信息。

总结

如果当前用户频繁使用同样的query进行查询,Query cache对于性能的提升是显而易见的。但是也有不太理想的情况,Query cache由于不仅依赖于执行的query,同时也依赖于当时的执行环境,比如SQL_MODE信息,字符集等,因此对于多用户共享Query cache,很难做到完全的共享。

另外,对于失效方式,目前MySQL做的并不到位,只要是表或表中的数据发生了变化便会引发相关cached queries失效,而更理想的方式是只有影响当前cached queries的执行结果的表的变化才引发相关cached plan失效。比如如果UPDATE语句并未修改某个cached queries的执行记过,其实可以不用对其失效。

我们会在接下来的文章中继续剖析Query cache的并发处理过程,敬请期待。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
9月前
|
SQL 关系型数据库 MySQL
MySQL技能完整学习列表3、SQL语言基础——1、SQL(Structured Query Language)简介——2、基本SQL语句:SELECT、INSERT、UPDATE、DELETE
MySQL技能完整学习列表3、SQL语言基础——1、SQL(Structured Query Language)简介——2、基本SQL语句:SELECT、INSERT、UPDATE、DELETE
136 0
|
4月前
|
SQL 关系型数据库 MySQL
MySQL死锁及源码分析!
MySQL死锁及源码分析!
MySQL死锁及源码分析!
|
6月前
|
SQL 关系型数据库 MySQL
MySQL的match WITH QUERY EXPANSION 模式是什么?如何使用?
【8月更文挑战第29天】MySQL的match WITH QUERY EXPANSION 模式是什么?如何使用?
92 4
|
6月前
|
关系型数据库 MySQL Java
解决com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large
这篇文章提供了解决MySQL JDBC驱动中`com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large`错误的步骤,主要是通过增加配置文件中的`max_allowed_packet`参数值并重启服务来允许更大的数据包传输。
解决com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large
|
5月前
|
SQL 关系型数据库 MySQL
MySQL 的 WITH QUERY EXPANSION 如何使用举例
【9月更文挑战第2天】MySQL 的 WITH QUERY EXPANSION 如何使用举例
86 0
|
5月前
|
存储 关系型数据库 MySQL
MySQL MATCH 函数如何使用 WITH QUERY EXPANSION?
【9月更文挑战第2天】MySQL MATCH 函数如何使用 WITH QUERY EXPANSION?
77 0
|
7月前
|
DataWorks 监控 关系型数据库
利用 DataWorks 数据推送定期推播 MySQL 或 StarRocks Query 诊断信息
DataWorks 近期上线了数据推送功能,能够将数据库查询的数据组织后推送到各渠道 (如钉钉、飞书、企业微信及 Teams),除了能将业务数据组织后推送,也能将数据库自身提供的监控数据组织后推送,这边我们就以 MySQL (也适用于StarRocks) 为例,定期推播 MySQL 的数据量变化等信息,帮助用户掌握 MySQL 状态。
145 1
|
7月前
|
存储 大数据 数据库
MySQL设计规约问题之为什么要利用pt-query-digest定期分析slow query log并进行优化
MySQL设计规约问题之为什么要利用pt-query-digest定期分析slow query log并进行优化
|
7月前
|
SQL 关系型数据库 MySQL
[已解决]com.mysql.cj.jdbc.exceptions. PacketTooBigException: Packet for query is too large (3,456,888
[已解决]com.mysql.cj.jdbc.exceptions. PacketTooBigException: Packet for query is too large (3,456,888
155 0
|
关系型数据库 MySQL 数据库
解决Navicat报错:2013 - Lost connection to MySQL server during query
解决Navicat报错:2013 - Lost connection to MySQL server during query
1387 0

相关产品

  • 云数据库 RDS MySQL 版