这应该是我们第一次讲到“缓存”的知识点。“缓存”是什么?
通俗讲把获取到的数据先临时存到一个地方(也就是说有时间限制的)。这个地方大多指的是内存,内存可以临时存放数据,而且从内存读取快(也有很多文件缓存,存到硬盘里)。获取的数据有可能是从硬盘里千挑万选读出来的,也有可能是通过复杂的计算得出来的结果。目的等下次再获取同样的数据时直接从内存读取,避免了重复做复杂的工作,这样效率会高很多。
缓存也有的目的是指数据不够多,暂时存起来,等到一定量后一块做处理。这个好比,只有你一人的快递,快递公司懒得送(不够油钱),等到快递多了,人家才送。
使用缓存,毋容置疑,可以极大提高访问效率,节省CPU开支。缺点是滞后,数据不及时。对于一些实时更新的数据不利于用缓存。
缓存在整个计算机世界里应该是无处不在。比如浏览器就使用了缓存:
这是访问一个网页请求的文件状态,http状态有些是200,有些是304。
304 的标准解释是:Not Modified 客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。
也就是304状态的文件,浏览器并没有再次从服务器获取,而是读取的本地缓冲文档。这是浏览器的一种缓冲,它可以减轻Web服务器的压力。
从图中可看出,大部分图片文件可以缓存,有些不可以缓存,想了解更多点击《http 304优化,了解客户端缓存》。
这节我们要讲的是不是浏览器缓存,而是MySQL的缓存。
MySQL也有自己的缓存机制。
在未开启缓存时,
两次查询时间消耗一致。
当开启了缓存:
第二次查询时,不会再费老大劲从硬盘获取数据,直接从内存缓存中取数据,效率立马就上去了。
怎么开启缓存呢?
依然是通过修改MySQL的几个变量。
show variables like 'query_cache%'可以看到这些信息。
query_cache_limit
允许 Cache 的单条 Query 结果集的最大容量,默认是1MB,超过此参数设置的 Query 结果集将不会被 Cache
query_cache_min_res_unit
设置 Query Cache 中每次分配内存的最小空间大小,也就是每个 Query 的 Cache 最小占用的内存空间大小
query_cache_size
分配给QC的内存。如果设为0,则相当于禁用QC。要注意QC必须使用大约40KB来存储它的结构,如果设定小于40KB,则相当于禁用QC。QC存储的最小单位是1024 byte,所以如果你设定了一个不是1024的倍数的值,这个值会被四舍五入到最接近当前值的等于1024的倍数的值。
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
query_cache_wlock_invalidate
控制当有写锁加在表上的时候,是否先让该表相关的 Query Cache失效,
1(TRUE),在写锁定的同时将使该表相关的所有 Query Cache 失效
0(FALSE),在锁定时刻仍然允许读取该表相关的 Query Cache
开启并设置大小:
注意事项:
1, 查询缓存存在判断是严格依赖于select语句本身的:严格保证SQL一致
SQL 语句大小写对 Query Cache 有影响。由于 Query Cache 在内存中是以 HASH 结构来进行映射,HASH 算法基础就是组成 SQL 语句的字符,所以必须要整个 SQL 语句在字符级别完全一致,才能在 Query Cache 中命中。
无论 MySQL收到的 Query 是单表还是多表或是包含子查询的 SQL,都被作为一个 Query,不会被分拆成多个 Query 来进行 Cache,包括Union 语句。
这也就是为什么连接查询触发缓存的概率低,推荐大家多用单表的基本查询。
2, 如果查询时包含动态数据,则不能被缓存。
3, 一旦开启查询缓存,MySQL会将所有可以被缓存的select语句都缓存。如果存在不想使用缓存的SQL执行,则可以使用 SQL_NO_CACHE语法提示达到目的:
在实际应用中,我们也可以通过一些状态值查看缓存的使用情况:
show status like '%qcache%';
Qcache_free_blocks: 表示查询缓存中目前还有多少剩余的blocks,如果该值显示较大,则说明查询缓存中的内存碎片过多了,可能在一定的时间进行整理。
Qcache_free_memory: 查询缓存的内存大小,通过这个参数可以很清晰的知道当前系统的查询内存是否够用,是多了,还是不够用,DBA可以根据实际情况做出调整。
Qcache_hits: 表示有多少次命中缓存。我们主要可以通过该值来验证我们的查询缓存的效果。数字越大,缓存效果越理想。
Qcache_inserts: 表示多少次未命中然后插入,意思是新来的SQL请求在缓存中未找到,不得不执行查询处理,执行查询处理后把结果insert到查询缓存中。这样的情况的次数,次数越多,表示查询缓存应用到的比较少,效果也就不理想。当然系统刚启动后,查询缓存是空的,这很正常。
Qcache_lowmem_prunes: 该参数记录有多少条查询因为内存不足而被移除出查询缓存。通过这个值,用户可以适当的调整缓存大小。
Qcache_not_cached: 表示因为query_cache_type的设置而没有被缓存的查询数量。
Qcache_queries_in_cache: 当前缓存中缓存的查询数量。
Qcache_total_blocks: 当前缓存的block数量。
Query Cache 为什么效率会非常高?
Query Cache 的查找,是在 MySQL 接受到客户端请求后在对 Query 进行权限验证之后,SQL 解析之前。
也就是说,当 MySQL 接收到客户端的SQL后,仅仅只需要对其进行相应的权限验证后就会通过 Query Cache 来查找结果,甚至都不需要经过 Optimizer 模块进行执行计划的分析优化,更不许要发生任何存储引擎的交互,减少了大量的磁盘 IO 和 CPU 运算,所以效率非常高。
一个 SQL 语句在 Query Cache 中的内容,在什么情况下会失效?
为了保证 Query Cache 中的内容与是实际数据绝对一致,当表中的数据有任何变化,包括新增,修改,删除等,都会使所有引用到该表的 SQL 的 Query Cache 失效。
为什么我的系统在开启了 Query Cache 之后整体性能反而下降了?
当开启了 Query Cache 之后,尤其是当我们的 query_cache_type 参数设置为 1 以后,MySQL 会对每个 SELECT 语句都进行 Query Cache 查找,查找操作虽然比较简单,但仍然也是要消耗一些 CPU 运算资源的。而由于 Query Cache 的失效机制的特性,可能由于表上的数据变化比较频繁,大量的 Query Cache 频繁的被失效,所以 Query Cache 的命中率就可能比较低下。所以有些场景下,Query Cache 不仅不能提高效率,反而可能造成负面影响。