今天说一说MySQL的查询缓存。查询缓存嘛,顾名思义就是提高查询性能用的,检索的时候不用去磁盘找了,直接把之前的缓存结果拿出来就返回了。
下面咱们讨论一下MySQL查询缓存的细节:
首先既然是查询缓存,那就只对SELECT语句起作用,这貌似是一句废话,但确实是如此。下面咱说的貌似不是废话的,查询缓存的结果是可以被会话共享的,也就是说同样的查询语句缓存,一个客户端刚查过的结果,另外一个客户端再查询是可以直接用这个缓存结果的。看起来很爽对不对,但是缓存真正应用起来还是有很多限制和使用场景要求的。
首先是缓存适合于那些不太经常修改的数据,原因很明显,缓存并不会造成读出陈旧数据,所以一旦数据被修改,缓存就作废了。对应频繁修改的表,缓存并不合适。倒是比较适合单行数据的缓存,尽管表本身经常有新数据插入,只要旧数据修改不频繁就不怕了。
第二点,对应SELECT语句中包含了函数的,缓存也无法应用,因为函数的值是不可控的,例如:CURDATE()获取当前日期 、RAND()取随机数等等都无法应用缓存。
第三点,缓存是对查询语句的精确匹配,也就是说只有查询语句有一点点不一样,都不能使用到之前的缓存。注意是一点点不一样都不行,包括大小写。也就是说, select * from t1 和 SELECT * FROM t1 这两个语句无法使用同一个缓存。
第四点,下列情况都无法应用查询缓存:
1) 用户定义函数或存储过程无法应用查询缓存;
2)用户变量或者局部存储程序变量无法应用查询缓存;
3)系统表都无法应用查询缓存: mysql库、INFORMATION_SCHEMA库,或者performace_schema库 (这点影响不大)
4)在MySQL 5.6.5及后续版本中分区表都无法应用查询缓存;
5) 以下格式语句的都无法应用查询缓存:
SELECT ....... LOCK IN SHARE MODE
SELECT ......... FOR UPDATE
SELECT ........ INTO OUTFILE ...
SELECT ....... INTO DUMPFILE .....
SELECT * FROM ... WHERE autoincrement_col IS NULL
6) 使用临时表的无法应用查询缓存;
7)没使用任何表的无法应用查询缓存;(这基本是废话)
8)语句产生警告的无法应用查询缓存;
大家看了以后是不是有些崩溃了,如此多的限制,貌似没啥可玩的了。大概也就我开始的那些场景比较适合应用了。不管怎么样,现在我们来看看如果设置缓存吧。
设置之前,先看看缓存开启了没有,执行语句:
SHOW VARIABLES LIKE 'have_query_cache'
mysql> SHOW VARIABLES LIKE 'have_query_cache';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| have_query_cache | YES |
+------------------+-------+
YES就代表是开启了。
设置缓存的大小, 通过设置系统变量 query_cahe_size来设置缓存的大小,如果设置为0则等于不应用缓存,也可以通过设置系统变量 query_cache_type=0,效果是一样的。默认情况下,查询缓存是关闭的。默认情况下,缓存大小为1M。如果设置的太小是会产生警告的,所以应该设置的大一点,所谓大1M就算是大了。 设置的时候要注意单位是byte。
除了设置全局系统变量,也可以通过设置客户端SESSION实现仅当前客户端禁用缓存
mysql> SET SESSION query_cache_type = OFF;
在开启的情况下,我们也可以强制我们想要的语句不进行缓存,可以使用 SQL_NO_CACHE选项, 例如: SELECT SQL_NO_CACHE id ,name FROM customer,那么这个查询客户表的语句就不会被缓存啦。
当结果被缓存的时候,不是在一个大的块中。而是按需要被存储在许多小块中,一个块被填满了,才会分配另一个新的块。因此内存分配也会花费很多的时间,所以合理的块大小就很重要。系统变量 query_cache_min_res_unit就是设置这个块大小的。默认情况下,这个值是4K,这个默认值可以适应绝大多数情况了。但是如果你有很多非常小的查询结果集,或者大部分查询结果集都非常大,就应该适当调整这个参数。
最后说说如何查看缓存的效果,现在缓存已经应用了,如果看效果呢? 执行语句 SHOW STATUS LIKE 'Qcache%' 查看
mysql> SHOW STATUS LIKE 'Qcache%';
+-------------------------+--------+
| Variable_name | Value |
+-------------------------+--------+
| Qcache_free_blocks | 36 |
| Qcache_free_memory | 138488 |
| Qcache_hits | 79570 |
| Qcache_inserts | 27087 |
| Qcache_lowmem_prunes | 3114 |
| Qcache_not_cached | 22989 |
| Qcache_queries_in_cache | 415 |
| Qcache_total_blocks | 912 |
+-------------------------+--------+
大家可以看到缓存hits命中数等等关心的数据。
再补充一点缓存维护的吧:
1)缓存时间长了,容易产生碎片,可以通过 FLUSH QUERY CACHE语句来清除碎片,清除碎片并不会将缓存结果本身清除掉。
2)那要清除缓存结果怎么办呢? 可以使用 RESET QUERY CACHE 清除缓存结果。执行 FLUSH TABLES语句可以带来同样的效果。