原理QueryCache(下面简称QC)是根据SQL语句来cache的。一个SQL查询若是以select开头,那么MySQL服务器将尝试对其使用 QC。每一个Cache都是以SQL文本做为key来存的。在应用QC以前,SQL文本不会被做任何处理。也就是说,两个SQL语句,只要相差哪怕是一个字符(例如大小写不同;多一个空格等),那么这两个SQL将使用不一样的一个CACHE。 不过SQL文本有可能会被客户端作一些处理。例如在官方的命令行客户端里,在发送SQL给服务器以前,会作以下处理: 过滤全部注释 去掉SQL文本先后的空格,TAB等字符。注意,是文本前面和后面的。中间的不会被去掉。 下面的三条SQL里,由于SELECT大小写的关系,最后一条和其余两条在QC里确定是用的不同的存储位置。而第一条和第二条,区别在于后者有个注释,在不一样客户端,会有不同的结果。因此,保险起见,请尽可能不要使用动态的注释。在PHP的mysql扩展里,SQL的注释是不会被去掉的。也就是三条 SQL会被存储在三个不一样的缓存里,虽然它们的结果都是同样的。 select * FROM people where name='surfchen'; select * FROM people where /*hey~*/name='surfchen'; SELECT * FROM people where name='surfchen'; 目前只有select语句会被cache,其余相似show,use的语句则不会被cache。 由于QC是如此前端,如此简单的一个缓存系统,因此若是一个表被更新,那么和这个表相关的SQL的全部QC都会被失效。假设一个联合查询里涉及到了表A和表B,若是表A或者表B的其中一个被更新(update或者delete),这个查询的QC将会失效。 也就是说,若是一个表被频繁更新,那么就要考虑清楚到底是否应该对相关的一些SQL进行QC了。一个被频繁更新的表若是被应用了QC,可能会加剧数据库的负担,而不是减轻负担。我通常的作法是默认打开QC,而对一些涉及频繁更新的表的SQL语句加上SQL_NO_CACHE关键词来对其禁用CACHE。这样能够尽量避免没必要要的内存操做,尽量保持内存的连续性。 那些查询很分散的SQL语句,也不该该使用QC。例如用来查询用户和密码的语句——“select pass from user where name='surfchen'”。这样的语句,在一个系统里,颇有可能只在一个用户登录的时候被使用。每一个用户的登录所用到的查询,都是不同的SQL 文本,QC在这里就几乎不起做用了,由于缓存的数据几乎是不会被用到的,它们只会在内存里占地方。 存储块 在本节里“存储块”和“block”是同一个意思 QC 缓存一个查询结果的时候,通常状况下不是一次性地分配足够多的内存来缓存结果的。而是在查询结果得到的过程当中,逐块存储。当一个存储块被填满以后,一个新的存储块将会被建立,并分配内存(allocate)。单个存储块的内存分配大小经过query_cache_min_res_unit参数控制,默认为 4KB。最后一个存储块,若是不能被所有利用,那么没使用的内存将会被释放。若是被缓存的结果很大,那么会可能会致使分配内存操做太频繁,系统系能也随之降低;而若是被缓存的结果都很小,那么可能会致使内存碎片过多,这些碎片若是过小,就颇有可能不能再被分配使用。 除了查询结果须要存储块以外,每一个SQL文本也须要一个存储块,而涉及到的表也须要一个存储块(表的存储块是全部线程共享的,每一个表只须要一个存储块)。存储块总数量=查询结果数量*2+涉及的数据库表数量。也就是说,第一个缓存生成的时候,至少须要三个存储块:表信息存储块,SQL文本存储块,查询结果存储块。而第二个查询若是用的是同一个表,那么最少只须要两个存储块:SQL文本存储块,查询结果存储块。 经过观察 Qcache_queries_in_cache和Qcache_total_blocks能够知道平均每一个缓存结果占用的存储块。它们的比例若是接近 1:2,则说明当前的query_cache_min_res_unit参数已经足够大了。若是Qcache_total_blocks比 Qcache_queries_in_cache多不少,则须要增长query_cache_min_res_unit的大小。 Qcache_queries_in_cache*query_cache_min_res_unit(sql 文本和表信息所在的block占用的内存很小,能够忽略)若是远远大于query_cache_size-Qcache_free_memory,那么能够尝试减少 query_cache_min_res_unit的值。 调整大小 若是Qcache_lowmem_prunes增加迅速,意味着不少缓存由于内存不够而被释放,而不是由于相关表被更新。尝试加大query_cache_size,尽可能使Qcache_lowmem_prunes零增加。 启动参数 show variables like 'query_cache%'能够看到这些信息。 query_cache_limit:若是单个查询结果大于这个值,则不Cache query_cache_size: 分配给QC的内存。若是设为0,则至关于禁用QC。要注意QC必须使用大约40KB来存储它的结构,若是设定小于 40KB,则至关于禁用QC。QC存储的最小单位是1024 byte,因此若是你设定了一个不是1024的倍数的值,这个值会被四舍五入到最接近当前值的等于1024的倍数的值。 query_cache_type:0 彻底禁止QC,不受SQL语句控制(另外可能要注意的是,即便这里禁用,上面一个参数所设定的内存大小仍是会被分配);1启用QC,能够在SQL语句使用 SQL_NO_CACHE禁用;2能够在SQL语句使用SQL_CACHE启用。 query_cache_min_res_unit:每次给QC结果分配内存的大小 状态 show status like 'Qcache%'能够看到这些信息。 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文本,查询结果。 另一篇: 若是 MySQL Server 负载比较高,处理很是繁忙的话,能够启动Query Cache 以加速响应时间,启动方法能够在my.cnf(Linux)或my.ini(Windows)中加入不如下项目:(Redhat下面是:/etc /my.cnf;Debian和Ubuntu是在/etc/mysql/my.cnf) query_cache_size = 268435456 query_cache_type = 1 query_cache_limit = 1048576 以上语句的设置中 query_cache_size 是分配256M内存给Query Cache;query_cache_type=1,是给全部的查询作Cache;query_cache_limit 是指定个别的查询语句1MB的内存。 这些数据能够根据本身的需求做出适当的更改,设置完成以后,保存文档,从新启动MySQL便可。 query_cache_type 0 表明不使用缓冲, 1 表明使用缓冲,2 表明根据须要使用。 设置 1 表明缓冲永远有效,若是不须要缓冲,就须要使用以下语句: SELECT SQL_NO_CACHE * FROM my_table WHERE ... 若是设置为 2 ,须要开启缓冲,能够用以下语句: SELECT SQL_CACHE * FROM my_table WHERE ... 用 SHOW STATUS 能够查看缓冲的状况: mysql> show status like 'Qca%'; +-------------------------+----------+ | Variable_name | Value | +-------------------------+----------+ | Qcache_queries_in_cache | 8 | | Qcache_inserts | 545875 | | Qcache_hits | 83951 | | Qcache_lowmem_prunes | 0 | | Qcache_not_cached | 2343256 | | Qcache_free_memory | 33508248 | | Qcache_free_blocks | 1 | | Qcache_total_blocks | 18 | +-------------------------+----------+ 8 rows in set (0.00 sec) 若是须要计算命中率,须要知道服务器执行了多少 SELECT 语句: mysql> show status like 'Com_sel%'; +---------------+---------+ | Variable_name | Value | +---------------+---------+ | Com_select | 2889628 | +---------------+---------+ 1 row in set (0.01 sec) 在本例中, MySQL 命中了 2,889,628 条查询中的 83,951 条,并且 INSERT 语句只有 545,875 条。所以,它们二者的和和280万的总查询相比有很大差距,所以,咱们知道本例使用的缓冲类型是 2 。 而在类型是 1 的例子中, Qcache_hits 的数值会远远大于 Com_select 。