MySQL中的Query Cache实现原理:将客户端请求的Query语句(仅限于select类型的Query)通过一定的hash算法进行一个计算,得到一个hash值,存放在一个hash桶中,同时将该Query的结果集(Result Set)也存放在一个内存Cache中。存放Query hash值的链表中每一个hash值所在节点的同时,还存放了该Query所对应的 Result Set的Cache所在内存地址,以及该Query 涉及的所有 Table的标识等一些其他的信息。系统接收一个Query 时限计算出它的hash值到Query Cache中取匹配,找到了就直接将之前缓存的 Result Set返回,后端任何一条数据的发生变化,会通知Query Cache将所有与该Table有关的 Query的Cache全部失效,释放占用的内存资源。个人感觉的和memcache的缓存差不多,只是比那个还方便,不用手工删除缓存。呵呵~
虽然Query Cache能带来性能的提升,但它也有很多弊端:(1) Query语句的hash 运算及hash查找资源的消耗。 (2) Query Cache的失效问题。如果表中的数据变化频繁,可能每次缓存到Query Cahce中的大 Cache 数据可能在被存入后很快因为表中的数据被改变而被清除,导致新的相同的 Query 进来后无法使用到之前的 Cache。 (3) Query Cache中缓存的是 Result Set ,而不是数据项,存在同一条记录被 Cache 多次的可能性,从而造成内存资源的过渡消耗。
适度使用 Query Cahce
首先避免在查询变化频繁的 Table 的Query上使用,而应该在那些查询频率较低的 Table 的 Query上使用。MySQL中针对 Query Cahce有两个专用的 SQL Hint(提示):SQL_NO_CACHE 和 SQL_CACHE,分别代表强制不适用 Query Cache 和强制使用 Query Cahce。
其次,对于那些变化非常少,大部分时候是静态的数据。可以添加SQL_CACHE的SQL Hint 强制MySQL使用 Query Cache。
最后,有些SQL 的 Result Set 很大,如果使用 Query Cache 很容易造成 Cache内存不足 或者将之前一些老的 Cache 冲刷出去。解决办法:使用 SQL_NO_CACHE 参数来强制它不适用 Query Cache; 另一种方法是通过设定“query_cache_limit”参数来控制 Query Cache中所缓存的最大 Result Set,系统默认为1M(1048576)。当某个 Query 的Result Set 大于"query_cache_limit"所设定的值时,Query Cache 是不会缓存这个Query的。
Query Cache 的相关系统参数变量和状态变量
执行:show variables like '%query_cache%' 得到Query Cache相关的系统参数变量:

"have_query_cache" : 该MySQL是否支持Query Cache
"query_cache_limit" :Query Cache存放的单个Query 最大 Result Set ,默认1M
"query_cache_min_res_unit":Query Cache每个Result Set 存放的最小内存大小,默认为4KB
"query_cache_size":系统中用于Query Cache内存的大小
"query_cache_type":系统是否打开了Query Cache的共能
执行: show status like 'Qcache%'; 命令得到Query Cache相关的状态变量。

"Qcache_free_blocks":Query Cache中目前还有多少剩余的blocks。如果该值显示较大,则说明Query Cache中的内存碎片过多了,要进行整理。
"Qcache_free_memory":Query Cache中目前剩余内存大小。
“Qcache_hits”:多少次命中。
"Qcache_inserts":多少次未命中然后插入。
"Qcache_lowmem_prunes":多少条Query因为内存不足而被清除出Query Cache。
"Qcache_not_cached":因为query_cache_type的设置而不能被缓存(cache)的Query数量。
"Qcache_queries_in_cache":当前Query Cache中缓存缓存的Query 数量。
"Qcache_total_blocks":当前Query Cache中的block数量。
摘自:《MySQL性能调优与架构设计》