mysql 把能够缓存的完整结果集缓存起来。如果查询语句包含任何不确定值的函数,得到的结果集是不确定的或者结果集大小超过了query_cache_limit限制,是不会被缓存的。
MYSQL是判断不出一个SQL能否被缓存的,只能判断查询缓存是否有相同的SQL和产生的结果集到底是否能被缓存起来。在解析SQL过程中如果发现SQL语句含有不确定函数,那么就会标记产生的结果集不被缓存。解析过程发生在检查查询缓存之后。
如果一张表发生任何改变,关于这张表的所有查询缓存都将失效。即使一些改变并不会改变之前查询的结果集。
Mysql 检查缓存命中的方法非常简单,首先执行一次不区分大小写的检查来验证查询是否以字母SEL开发,如果满足则会检查查询缓存中是否有相同的查询语句,只要字符大小写,空格或者注释有一点点不同,则会被认为不同的查询。开头有空格除外。如果找到有相同的查询语句,则直接把缓存的结果集发送给客户端,这样就不会再执行解析和执行等操作。
SELECT * FROM TABNAME 与 select * from TABNAME 就被认为是两条不同的SQL语句,因为这个时候没有进行任何解析。
5.1版本中,视图产生的查询可以被缓存。
flush query cache 主要用于整理碎片,不会清理查询缓存, reset query cache则会清空查询缓存,包括之前已经缓存的查询语句结果集。
如果启动查询缓存,每次查询语句执行之前会先在查询缓存里查找是否已存在,要么在缓存中找到相应结果集直接返回给客户端,要么进行解析与执行,在解析过程中就知道产生的结果集能否被缓存,因此产生结果集后要么先在缓存里缓存起来再返回给客户端要么直接返回给客户端。
当一个查询SQL发送到MYSQL服务后,如果查询缓存里存在相同的SQL,Qcache_hits值加1,如果没有,就继续解析与执行,如果产生的集结集能被缓存那么Qcache_inserts + 1,和Com_select + 1,如果不能被缓存则Qcache_not_cached + 1与Com_select + 1.查询缓存命中率Qcache_hits /Qcache_hits + Com_select. 不能缓存率 Qcache_not_cached /Com_select. 能缓存率Qcache_inserts/Com_select. 其实SELECT查询的总数量等价于:Com_select + Qcache_hits + queries with errors found by parser. 但是我们可以忽略queries with errors found by parser.
内存块分配:服务启动开始,就会分配好query_cache_size定义的内存块,最开始只有一个大内存块,当有结果集需要请求时,因为最开始是不知道结果集的大小的,只知道有结果集需要被缓存,所以开始就会从大内存块里分配出一个query_cache_min_res_unit大小的内存块,如是不够,则会再分一个内存块,大小也是query_cache_min_res_unit。如果有多余空闲的内存,就会被切割出去当作一个自由块。如果发现最终结果集的大小比query_cache_limit还大时,就会放弃不再缓存,并把之前已经缓存起来的数据也丢掉。(当然,这里面实际的过程是相当复杂的,我这里只是最简单的理解)
show global 里关于查询缓存有几个状态值,这里做简单介绍:
Qcache_free_blocks :上文称之为自由块。其实也可以称之为碎片,因为它没有存储数据空闲在那里。最块的情况是一个存储块接着一个空闲块然后又是存储块然后又是空闲块,这样的话存储块与空闲块的比例就是1:1,Qcache_free_blocks = Qcache_total_blocks / 2, 这种情况就表明空闲块数量太大,碎片情况非常严重。
Qcache_free_memory:空闲内存。总查询缓存大小减去已经缓存起来的数据大小。空闲内存估计的统计是包含自由块大小在里面的。
Qcache_hits :查询缓存命中次数。只要是从查询缓存取出的结果集,Qcache_hits +1.
Qcache_inserts :将结果集保存到查询缓存的次数。只要结果集符合要求就会被保存到查询缓存中去,Qcache_inserts+1
Qcache_lowmem_prunes :由于查询缓存内存不足,使用LRU策略将最近最小使用的查询结果集从查询缓存中移出。注意:至少移出N条已经被缓存起来的SQL才能有足够的内存来存放当前这条SQL,那么 Qcache_lowmem_prunes + N
Qcache_not_cached :如果判断产生的结果集不能被缓存起来,像查询SQL含有不确定函数,如果结果集大于query_cache_limit限制,Qcache_not_cached +1
Qcache_queries_in_cache :当前此时此刻,查询缓存中已经保存的查询结果集个数。
Qcache_total_blocks :当前查询缓存中,总共已分配的内存块总数,包含真实存储数据的存储块和自由块。