Query Cache (查询缓存, 以下简称QC), 查询SELECT语句记起产生的数据结果, 如果以后遇到相同的语句时(语句完全一样) 服务器从会返回查询缓存的结果, 而不是分析数据表. QC适用于一些静态页面, 或者页面不经常更新的信息。
由于QC需要缓存最新数据结果, 所以当表中数据有变化时(INSERT,UPDATE,DELETE或者其他可能产生数据变化的操作),都会导致QC被刷新。
查看QC:
SHOW STATUS LIKE 'Qcache%';
查询结果:
Variable_name | Value |
---|---|
Qcache_free_blocks | 2577 |
Qcache_free_memory | 8904480 |
Qcache_hits | 1548269 |
Qcache_inserts | 1287698 |
Qcache_lowmem_prunes | 86872 |
Qcache_not_cached | 884767 |
Qcache_queries_in_cache | 6315 |
Qcache_total_blocks | 15213 |
- Qcache_free_blocks: 当一个表被更新之后, 和它相关的cache blocks将被free。 但是这个block依然可能存在队列中, 除非是在队列的尾部。这些blocks将被统计到这个值来, 可以用FLUSH QUERY CACHE语句来清空free blocks。
- Qcache_free_memory:可用内存, 如果很小, 考虑增加query——cache_size。
- Qcache_hits:自mysql进程启动起,cache的命中数量。
- Qcache_inserts:自mysql进程启动起, 被增加进QC的数量。
- Qcache_lowmem_prunes:由于内存过少而导致QC被删除的条数。加大query_cache_size,尽可能保持这个值0增长。
- Qcache_not_cached:自mysql进程启动起,没有被cache的只读查询数量(包括select,show,use,desc等)。
- Qcache_queries_in_cache:当前被cache的SQL数量。
- Qcache_total_blocks:在QC中的blocks数。一个query可能被多个blocks存储,而这几个blocks中的最后一个,未用满的内存将会被释放掉。例如一个QC结果要占6KB内存,如果query_cache_min_res_unit是4KB,则最后将会生成3个blocks,第一个block用来存储sql语句文本,这个不会被统计到query+cache_size里,第二个block为4KB,第三个block为2KB(先allocate4KB,然后释放多余的2KB)。每个表,当第一个和它有关的SQL查询被CACHE的时候,会使用一个block来存储表信息。也就是说,block会被用在三处地方:表信息,SQL文本,查询结果。
在一个更新频率非常低而且只读查询频率非常高的场景下,打开QC还是比较有优势的,其他场景下, 则不建议使用,因为起大多只会增加查询负担,而不会增加查询效率,而且,QC一般维持在100M以内就足够了。
而且QC也不适用于下面几个场景:
1、子查询或者外层查询;
2、存储过程、存储函数、触发器、event中调用的SQL,或者引用到这些结果的;
3、包含一些特殊函数时,例如:BENCHMARK()、CURDATE()、CURRENT_TIMESTAMP()、NOW()、RAND()、UUID()等等;
4、读取mysql、INFORMATION_SCHEMA、performance_schema 库数据的;
5、类似SELECT…LOCK IN SHARE MODE、SELECT…FOR UPDATE、SELECT..INTO OUTFILE/DUMPFILE、SELECT..WHRE…IS NULL等语句;
6、SELECT执行计划用到临时表(TEMPORARY TABLE);
7、未引用任何表的查询,例如 SELECT 1+1 这种;
8、产生了 warnings 的查询;
9、SELECT语句里加了 SQL_NO_CACHE 关键字;
而且,MySQL在从QC中取回结果钱, 会先判断执行SQL的用户是否有全部库,表的SELECT权限, 如果没有,也不会使用QC。
最重要的一点是,在MySQL里QC是由一个全局的锁在控制, 每次更新QC的内存块都需要进行锁定。
例如,一次查询的结果是20KB,当前query_cache_min_res_unit 值设置为 4KB(默认值就是4KB,可调整),那么么本次查询结果共需要分为5次写入QC,每次都要锁定,可见其成本有多高。
总结就是:
如果线上99%以上都是只读,几乎无更新,那么可以考虑开启QC,否则,就别开了(默认是开启的)
关闭方法:
- 1.同时设置选项 query_cache_type = 0 和 query_cache_size = 0;
- 2.如果用源码编译MySQL的话,编译时增加参数 --without-query-cache 即可;
python技术交流群: 577128300