13.MySQL查询缓存
# 01.MySQL查询缓存
# 1、概述
- 为了提高完全相同的查询语句的响应速度,MySQL Server 会对查询语句进行 Hash 计算得到一个 Hash 值
- MySQL Server 不会对 SQL 做任何处理,SQL 必须完全一致 Hash 值才会一样
- 得到 Hash 值之后,通过该 Hash 值到查询缓存中匹配该查询的结果
- MySQL Server 会对查询语句进行 Hash 计算得到一个 Hash 值
- 再次查询如果 Hash 值完全一样,就算匹配了缓存
- 如果匹配(命中),则将查询的结果集
直接返回给客户端
,不必再解析、执行查询
- 如果没有匹配(未命中),则将 Hash 值和结果集保存在查询缓存中,以便以后使用
# 2、缓存规则
- 查询缓存会将查询语句和结果集保存到内存(key 是查询语句,value 是查询的结果集
- 缓存的结果是通过 sessions 共享的,所以一个 client 查询的缓存结果,另一个 client 也可以使用
- SQL 必须完全一致才会导致查询缓存命中(大小写、空格、使用的数据库、协议版本、字符集等必须一致)
- 不缓存查询中的子查询结果集,仅缓存查询最终结果集
- 不确定的函数将永远不会被缓存, 比如
now()
、curdate()
、last_insert_id()
、rand()
等 - 不缓存产生告警(Warnings)的查询
- 太大的结果集不会被缓存 (< query_cache_limit)
- 如果查询中包含任何用户自定义函数、存储函数、用户变量、临时表、MySQL 库中的系统表,其查询结果也不会被缓存
- 缓存建立之后,MySQL 的查询缓存系统会跟踪查询中涉及的每张表
- 如果这些表(数据或结构)发生变化,那么和这张表相关的所有缓存数据都将失效
- MySQL 缓存在分库分表环境下是不起作用的
- 不缓存使用
SQL_NO_CACHE
的查询
# 3、缓存机制中的内存管理
查询缓存是完全存储在内存中的,所以在配置和使用它之前,我们需要先了解它是如何使用内存的
MySQL 查询缓存使用内存池技术,自己管理内存释放和分配,而不是通过操作系统
内存池使用的基本单位是变长的 block, 用来存储类型、大小、数据等信息
一个结果集的缓存通过链表把这些 block 串起来
block 最短长度为
query_cache_min_res_unit
当服务器启动的时候,会初始化缓存需要的内存,是一个完整的空闲块
当查询结果需要缓存的时候,先从空闲块中申请一个数据块为参数
query_cache_min_res_unit
配置的空间即使缓存数据很小,申请数据块也是这个,因为查询开始返回结果的时候就分配空间,此时无法预知结果多大
分配内存块需要先锁住空间块,所以操作很慢,MySQL 会尽量避免这个操作,选择尽可能小的内存块
如果不够,继续申请,如果存储完时有空余则释放多余的
但是如果并发的操作,余下的需要回收的空间很小,小于
query_cache_min_res_unit
,不能再次被使用,就会产生碎片
# 4、查询缓存的优缺点
优点
- 查询缓存的查询,发生在 MySQL 接收到客户端的查询请求、查询权限验证之后和查询 SQL 解析之前
- 不需要发生任何存储引擎的交互
- 由于查询缓存是基于内存的,效率非常高
缺点
- 对每条 sql 都需要 hash计算,会带来一定开销
- 如果表的变更比较频繁缓存的失效率非常高
- 查询语句不同,但查询结果相同的查询都会被缓存,这样便会造成内存资源的过度消耗
- 查询语句的字符大小写、空格或者注释的不同,查询缓存都会认为是不同的查询(因为他们的 Hash 值会不同)
- 相关系统变量设置不合理会造成大量的内存碎片,这样便会导致查询缓存频繁清理内存
# 5、总结
MySQL 中的查询缓存虽然能够提升数据库的查询性能,但是查询同时也带来了额外的开销,每次查询后都要做一次缓存操作,失效后还要销毁。
查询缓存是一个适用较少情况的缓存机制
如果你的应用对数据库的更新很少,那么查询缓存将会作用显著
比较典型的如博客系统,一般博客更新相对较慢,数据表相对稳定不变,这时候查询缓存的作用会比较明显
简单总结一下查询缓存的适用场景
表数据修改不频繁、数据较静态
查询(Select)重复度高
查询结果集小于 1 MB
简单总结一下查询缓存不适用的场景
表中的数据、表结构或者索引变动频繁
重复的查询很少
查询的结果集很大
根据我们的经验,在高并发压力环境中查询缓存会导致系统性能的下降,甚至僵死
如果你一 定要使用查询缓存,那么不要设置太大内存,而且只有在明确收益的时候才使用(数据库内容修改次数较少)