众所周知,Mysql Query Cache能够存储select语句及其产生的数据结果,Mysql中的参数query_cache_type都能控制Query Cache的开启和关闭功能,实现mysql对于数据的缓存功能。对于innodb引擎的表来说,数据缓存于InnoDB Buffer Pool中,如图1,在下一次执行查询语句时,在Query Cache有可能会从InnoDB Buffer Pool里读取结果。
图1
在MySQL中,Query Cache功能默认都是打开的,query_cache_type:控制Query Cache功能的开关,可以设置为0(OFF),1(ON)和2(DEMAND)三种,意义分别如下:
0(OFF):关闭Query Cache功能,任何情况下都不会使用Query Cache;
1(ON):开启Query Cache功能,但是当SELECT语句中使用的SQL_NO_CACHE提示后,将不使用Query Cache;
2(DEMAND):开启Query Cache功能,但是只有当SELECT语句中使用了SQL_CACHE提示后,才使用Query Cache。
当mysql接收到一条select类型的query时,mysql会对这条query进行hash计算而得到一个hash值,然后通过该hash值到query cache中去匹配,如果没有匹配中,则将这个hash值存放在一个hash链表中,同时将query的结果集存放进cache中,存放hash值的链表的每一个hash节点存放了相应query结果集在cache中的地址,以及该query所涉及到的一些table的相关信息;如果通过hash值匹配到了一样的query,则直接将cache中相应的query结果集返回给客户端。如果mysql任何一个表中的任何一条数据发生了变化,便会通知query cache需要与该table相关的query的cache全部失效,并释放占用的内存地址。
Mysql Query Cache优点很明显,对于一些频繁select query,mysql直接从cache中返回相应的结果集,而不用再从表table中取出,减少了系统的IO开销。
即使Mysql Query Cache的收益很明显,但是也不能忽略其缺点:
1. query语句的hash计算和hash查找带来的资源消耗。mysql会对每条接收到的select类型的query进行hash计算然后查找该query的cache是否存在,虽然hash计算和查找的效率已经足够高了,一条query所带来的消耗可以忽略,但一旦涉及到高并发,有成千上万条query时,hash计算和查找所带来的开销就的重视了;
2. query cache的失效问题。如果表变更比较频繁,则会造成query cache的失效率非常高。表变更不仅仅指表中的数据发生变化,还包括结构或者索引的任何变化;
3.对于不同sql但同一结果集的query都会被缓存,这样便会造成内存资源的过渡消耗。sql的字符大小写、空格或者注释的不同,缓存都是认为是不同的sql(因为他们的hash值会不同);
4. 相关参数设置不合理会造成大量内存碎片。
Mysql Query Cache有利有弊,合理的使用query cache可以使其发挥优势,并且有效的避开其劣势。
1. 并不是所有表都适合使用query cache。造成query cache失效的原因主要是相应的table发生了变更,那么就应该避免在变化频繁的table上使用query cache。
2. 设置合理的参数变量和状态变量。
首先查看query cache的系统变量。
query_cache_limit:允许Cache的单条Query结果集的最大容量,默认是1MB,超过此参数设置的Query结果集将不会被Cache。
query_cache_min_res_unit:设置Query Cache中每次分配内存的最小空间大小,也就是每个Query的Cache最小占用的内存空间大小。
query_cache_size 表示系统中用于query cache的内存大小。
query_cache_wlock_invalidate:控制当有写锁定发生在表上的时刻是否先失效该表相关的Query Cache,如果设置为1(TRUE),则在写锁定的同时将失效该表相关的所有Query Cache,如果设置为0(FALSE)则在锁定时刻仍然允许读取该表相关的Query Cache。
查看query cache相关的状态变量。
Qcache_free_blocks :表示query cache中目前还有多杀剩余的blocks,如果该值显示较大,则说明query cache中的内存碎片较多,需要进行整理了;
Qcache_free_memory :表示query cache目前剩余的内存大小;
Qcache_hits :表示query cache有多少次命中;
Qcache_inserts: 表示未命中cache后将结果集再写入到cache中的次数;
Qcache_lowmem_prunes: 表示多少条query因为内存不足而被清除出query_cache;
Qcache_not_cached :表示因为query_cache_type的设置或者不能被cache的query的数量;
Qcache_queries_in_cache: 表示当前cache的query的数量;
Qcache_total_blocks :当前query cache中的block数量。
通过上述这些状态变量可以了解到query cache的运行状况,从而可以调整相应的系统参数的值。
总结:Mysql Query Cache的开启有利也有弊,在大量读少量写的业务场景下可以开启,否则建议关闭,关闭方法有两种,第一种:同时设置选项 query_cache_type = 0和query_cache_size = 0;第二种:如果用源码编译MySQL的话,编译时增加参数--without-query-cache即可。