MySql查询缓存学习总结

首先了解一下Mysql执行一个查询的过程

(1)客户端发送一条查询给服务器
(2)服务器先检查缓存,如果命中缓存,立即返回缓存结果。否则进入下一阶段
(3)然后服务器进行sql解析、预处理,再由优化器生产对应的执行计划
(4)查找到结果,存入查询缓存中并返回给客户端

开启查询缓存的好处

Mysql查询缓存保存了查询返回的完整结果。当查询命中该缓存时,立刻返回结果,解析、优化和执行阶段。极大的加快了查询的响应时间,特别是比较慢的sql和繁忙的系统。

缓存未命中的可能原因

缓存存放在一个引用表中,通过一个哈希值引用。因此这个哈希值的包含的因素就非常重要了,它直接关系到缓存是否能够命中。这些因素包含:查询本身、当前查询的数据库、客户端协议的版本等一些其它可能会影响返回结果的信息。

(1)判断缓存是否命中时,是直接使用所写的SQL语句和客户端发送过来的其他原始信息。因此任何字符的不同都会导致不能命中的问题。比如说sql多了一个空格、少一个一个空格、大小写不一致、查询条件位置互换等等。
(2)包含一些不确定的数据时,则不会被缓存:比如说NOW()、DATE()等函数,还有用户自定义的函数、临时表、存储函数、用户变量、临时表、z子查询等,都不会被缓存
需注意的是:查询中包含一个不确定的函数时,查询结果不会被缓存到查询缓存中。在检查查询缓存时,还没有进行解析SQL语句,所以这样的查询同样需要先去查询缓存中去寻找是否有查询结果。
在检查查询缓存之前,Mysql只做一件事,那就是通过检查SQL语句是否是以SEL开头(大小不敏感)
(3)查询结果太大导致无法缓存。阈值:query_cache_limit
(4)由于查询缓存的内存用完了,mysql会将之前的某些缓存逐出
(5)数据的修改新增会导致缓存失效

查询缓存的缺点

(1)对读和写都会带来额外的消耗
因为读查询之前必须检查是否命中缓存。
执行完读库后如果查询缓存中没有缓存这个查询,会将其结果存入查询缓存中。
在新增或更新后,必须将对应表的所有缓存设置成失效,如果查询缓存已经非常大或者碎片很多时,对系统有很大的消耗。
(2)特别时上面所说任何字符的不同都会是一个新的查询缓存,如果没有统一的编码规则,会导致同一个查询sql因这个问题出现多个缓存。
(3)查询缓存操作是一个加锁排他操作
(4) 如果查询缓存使用了很大的内存时,缓存失效操作可能会成为一个非常严重的问题瓶颈。因为这个操作是靠一个全局的锁操作保护的,所有需要做该操作的查询都要等待这个锁(不管是检测是否命中缓存 还是缓存失效都需要等待这个全局锁)。因此如果缓存中存放了大量的查询结果,缓存失效操作都可能会导致整个系统僵死一会。
(5)Innodb的事务的特性会限制查询缓存的使用。Innodb的多版本特性会暂时对其他事务屏蔽,在这个事务提交前,这个表的相关查询是无法被缓存的。

基于这些问题,不推荐打开查询缓存。

查询缓存如何使用内存

使用的内存包含两部分:

(1)维护除查询结果的相关的数据,这和文件系统有些类似:需要一些内存专门用来确定哪些内存目前是可用的、哪些内存时已将用掉的、哪些用来存储数据表和查询结果之间的映射、哪些用来存储查询字符串和查询结果。大概需要40KB的内存资源
(2)用于查询缓存的内存:这块内存被分成一个个的变长数据块。每个数据块中,存储了自己的类型、大小和存储数据本身,还外加指向前一个和后一个的数据块的指针。

原理

当服务器启动的时候,先初始化查询缓存需要的内存(query_cache_size减去维护元数据结构消耗),这个内存池是一个完整的空闲块。
当有查询结果需要缓存的时候,mysql先从大的空间中申请一个数据块用于存储结果,这个数据块必须是大于参数query_cache_min_res_unit的配置,即使查询结果远远小于此。在查询结果返回的就开始申请内存空间,在此时无法知道返回结果的大小,这个是导致碎片的很大原因。
分配内存块是一个非常慢的操作,因为需要先锁住空间块,然后再找到合适大小的数据块。当一个数据块全部用完的时候,但仍有剩余数据需要存储,那么mysql会申请一块新的数据块继续存储结果数据。当查询查询完成时,如果与空闲空间紧挨着的申请的数据块还有剩余内存空间时,mysql会将其释放,并入空闲内存部分。
但是如果在并发操作下,第一个查询和第二个查询之间留下了小于query_cache_min_res_unit的空间,由于小于query_cache_min_res_unit不能再次被查询缓存使用,就产生了碎片
注:缓存失效时,也可能会导致留下太小的数据块无法在后续缓存中使用,也就是说产生大量碎片
正常情况下:
在这里插入图片描述
并发情况下:
在这里插入图片描述

相关参数配置

query_cache_type

是否开启查询缓存。OFF(0)–>关闭查询缓存 ON(1)–>打开查询缓存 DEMAND(2)–>只有在查询语句中加了 SQL_CACHE 才会放入查询缓存.
该参数只能修改配置文件并重启数据库生效

 show VARIABLES like 'query_cache_type';

query_cache_size

查询缓存可以使用的总的内存空间。设置必须是1024的倍数;该参数可以动态修改

 show VARIABLES like 'query_cache_size';
 set GLOBAL query_cache_size=1024*1024;

query_cache_min_res_unit

分配的内存块大小的最小单位;该参数可以动态修改

 show VARIABLES like 'query_cache_min_res_unit'
 set GLOBAL query_cache_min_res_unit=1024*4;

query_cache_limit

限制缓存的最大结果。如果缓存结果比该值大的时候,则不缓存该结果;由于数据开始生成时就开始缓存了,
因此当生成完成之后才能判断缓存大小,当大小比该值大的时候就把该缓存删除;该参数可以动态修改
所以如果知道当前sql查询出的结果大于该设置的值时,建议sql语句上增加SQL_NO_CACHE来避免查询缓存带来的消耗

 show VARIABLES like 'query_cache_limit'
 set GLOBAL query_cache_limit=1024*1024;

query_cache_wlock_invalidate

如果该数据表被其他线程锁住,是否还要从缓存中返回结果。默认是OFF。如果设置成ON,则不会从缓存中读取该数据,但是会增加锁等待

 show VARIABLES like 'query_cache_wlock_invalidate'

查看查询缓存的使用详情

 SHOW STATUS LIKE 'Qc%';

在这里插入图片描述

Qcache_hits–>查询缓存命中次数 Qcache_inserts–>查询缓存中插入条数 Qcache_free_memory–>查询缓存剩余内存 Qcache_not_cached–>查询没有被缓存的次数
Qcache_free_blocks–> 查询缓存中空闲的内存块,该值越大表示碎片越多。如果没有任何查询的情况下,碎片数=Qcache_free_blocks-1
Qcache_total_blocks–> 查询缓存中总的内存块,包括使用的和未使用的
Qcache_queries_in_cache --> 当前查询缓存中cache的Query 数量;

总结

如果非必要就尽量不要开启查询缓存,并且把query_cache_size设置成0。如果需要使用查询缓存的话,建议将query_cache_type参数设置成DEMAND,在需要的使用在sql语句中加SQL_CACHE指定使用查询缓存。另外需要规范统一的编码规则。同时还需要面对查询缓存上的一些性能问题。
其实使用INNODB的缓存池的缓存其实也差不多了,不建议再开启查询缓存。由于各种性能问题,Mysql8中已经把查询缓存这个功能移除掉了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值