说到缓存,大家应该都不陌生,从静态页面缓存到服务端动态缓存,再到数据库级别缓存等等。因为内存的读写速度比磁盘快若干倍,所以缓存是比较常用的提高性能的方式。
MySQL也有自己的缓存机制,可以针对sql进行缓存。比如我们发送select * from my_tb这么一个查询,MySQL首先检索内存中是否有数据并且数据是否过期,如果没有数据或者数据已经过期就去数据库中查找,如果有数据并且没有过期就直接返回数据。对于sql的匹配规则非常简单,就是字符串的比较,只要字符串相同,那么就认为是同一个查询。这里的字符串相同并不是表示sql语义相同,而是查询的sql字符串相同,空格也不行。MySQL的缓存是对全部的sql有效的, 也就是说一旦开启了查询缓存,那么对所有的sql查询默认都是开启的。
可以通过下面的SQL查看当前查询缓存相关参数状态:
SHOW VARIABLES LIKE '%query_cache%';
输出结果类似下面:
query_cache_type
查询缓存类型,有0、1、2三个取值。0则不使用查询缓存。1表示始终使用查询缓存。2表示按需使用查询缓存。
如果query_cache_type为1而又不想利用查询缓存中的数据,可以用下面的SQL:
SELECT SQL_NO_CACHE * FROM ···
如果值为2,要使用缓存的话,需要使用SQL_CACHE开关参数:
SELECT SQL_CACHE * FROM ···
query_cache_size
默认情况下query_cache_size为0,表示为查询缓存预留的内存为0,则无法使用查询缓存。所以我们需要设置query_cache_size的值:
SET GLOBAL query_cache_size = 134217728;
注意上面的值如果设得太小不会生效。比如我用下面的SQL设置query_cache_size大小:
SET GLOBAL query_cache_size = 4000;
SHOW WARNINGS;
会返回下面的结果:
缓存条件
查询缓存可以看做是SQL文本和查询结果的映射。如果第二次查询的SQL和第一次查询的SQL完全相同(注意必须是完全相同,即使多一个空格或者大小写不同都认为不同)且开启了查询缓存,那么第二次查询就直接从查询缓存中取结果,可以通过下面的SQL来查看缓存命中次数(是个累加值):
SHOW STATUS LIKE 'Qcache_hits';
另外即使完全相同的SQL,如果使用不同的字符集、不同的协议等也会被认为是不同的查询而分别进行缓存。
不会缓存结果可能的情况:
1.当查询语句中有一些不确定的数据时,则不会被缓存。如包含函数NOW(),CURRENT_DATE()等类似的函数,或者用户自定义的函数,存储函数,用户变量等都不会被缓存。
2.当查询的结果大于query_cache_limit设置的值时,结果不会被缓存。
3.对于InnoDB引擎来说,当一个语句在事务中修改了某个表,那么在这个事务提交之前,所有与这个表相关的查询都无法被缓存。因此长时间执行事务,会大大降低缓存命中率。
4.查询语句中使用了LOCK IN SHARE MODE、FOR UPDATE的语句,以及事务隔离级别为:Serializable情况下,所有查询语句都不能缓存。
5.对临时表的查询操作。
6.存在警告信息的查询语句。
7.之前缓存了查询结果,但是由于查询缓存内存不足,MySQL将某些缓存逐出,导致未命中。
8.缓存失效操作太多。数据修改,内存不足,缓存碎片都会导致缓存失效。
缓存数据失效时机
在表的结构或数据发生改变时,查询缓存中的数据不再有效。有这些INSERT、UPDATE、 DELETE、TRUNCATE、ALTER TABLE、DROP TABLE或DROP DATABASE会导致缓存数据失效。所以查询缓存适合有大量相同查询的应用,不适合有大量数据更新的应用。
查询缓存带来的额外消耗:
1.在查询之前必须先检查是否命中缓存。
2.如果这个查询可以被缓存,那么执行完成后,MySQL发现查询缓存中没有这个查询,则会将结果存入查询缓存,这会带来额外的系统消耗。
3.写入或更新数据时,MySQL必须将对应表的所有缓存都设置失效。如果查询缓存很大或者碎片很多时,这个操作可能带来很大的系统消耗。
但这些开销相对来说较小,所以查询缓存对于查询多于写操作的情况还是很有好处的。
碎片如何产生:
假设查询的结果非常小,服务器在并发的向两个链接返回结果,这是在向A和B两个内存块写入数据,返回完结果后回收剩余的空间时,A剩余的空间小于query_cache_min_res_unit设置的值,这样就不能再次被查询缓存使用,从而产生了碎片,B剩余的空间则会释放,并入空闲内存部分。
可以使用下面三个SQL来清理查询缓存:
1、FLUSH QUERY CACHE; // 清理查询缓存内存碎片。
2、RESET QUERY CACHE; // 从查询缓存中移出所有查询。
3、FLUSH TABLES; //关闭所有打开的表,同时该操作将会清空查询缓存中的内容。
不懂的留言,每天一篇分享,玩转我们共同的爱好!
你也来投搞!