query_cache_limit:该参数设置单条查询语句允许缓存到Query Cache中的最大结果容量值,1048576(1M)是它的默认值。也就是说如果查询语句返回的查询结果集合大于1M,则这个查询结果集合不会缓存到Query Cache区域。
query_cache_min_res_unit:该参数设置Query Cache每次分配内存的最小大小,默认值为4096(4KB)。
query_cache_type:注意,既是单独设置query_cache_size为0,也不会使MySQL服务关闭Query Cache功能。一定要设置query_cache_type参数为0(OFF)才行。另外当该参数值为1(ON)时,代表开启Query Cache功能,此时必须在SQL查询语句中明确使用SQL_NO_CACHE,才能关闭这条查询语句的Query Cache功能;该参数的值还可以为2(DEMAND),此时只有当SQL查询语句明确使用SQL_CACHE关键字,才能让这条查询语句使用Query Cache功能。
query_cache_wlock_invalidate:该参数设置Query Cache中数据的失效时刻(非常重要)。如果该值为1(ON),则在数据表被写锁定的同时该表中数据涉及的所有Query Cache都将失效;如果该值为0(OFF),则表示在数据表写锁定的同时,Query Cache中该数据表的相关数据都还继续有效。
您还可以通过“show status like ‘Qcache%’”语句查询当前MySQL服务中Query Cache的工作状态
# show status like \'Qcache%\' Qcache_free_blocks 0 Qcache_free_memory 0 Qcache_hits 0 Qcache_inserts 0 Qcache_lowmem_prunes 0 Qcache_not_cached 0 Qcache_queries_in_cache 0 Qcache_total_blocks 0各位读者看到以上示例中所有和Query Cache相关的状态值都为0,这是因为在演示的MySQL服务中默认关闭了Query Cache功能(主要是设置了query_cache_type的值为0)。不过以上展示的Query Cache状态信息中一些状态项还是要进行说明:
Qcache_free_memory:该指标说明了当前Query Cache专用内存区域还有多少剩余内存。
Qcache_hits:该指标说明当前Query Cache从MySQL服务启动到现在的命中次数。
Qcache_lowmem_prunes:该指标说明因为Query Cache内存不足而被清除的查询结果数量。
其它的状态项可参见MySQL的官方文档《The MySQL Query Cache》
4-2-2、Query Cache的局限性和使用建议为什么MySQL Version 5.5及以后的版本会默认关闭Query Cache功能呢?这至少说明官方并不建议在任何场景下都是用Query Cache功能,甚至是大多数场景下。首先,Query Cache存在功能局限性:
早期版本(Version 5.1)的Query Cache功能并不支持变量绑定,也就是说类似“select * from A where field = ?”这样的SQL查询结果不会被放入Query Cache中。
存储过程、触发器等基于数据库引擎类型工作的特定功能,如果其中使用了查询语句,这些查询语句的结果也不会放入Query Cache中。
复杂的SQL查询中,往往包含多个子句。这些子句的查询结果能够被放入Query Cache中。但是用于包含这些子句的外部查询结果却不能放入Query Cache。
以上提到的Query Cache功能局限性在每次MySQL版本升级的过程中,MySQL开发团队都逐渐进行了调整,所以这写功能性限制并不是什么太大的问题。例如以上说到的在存储过程中的SQL查询不会加入到Query Cache中,这个实际上就不是什么大问题,目前来看业务系统中业务逻辑处理部分还都是放在上层业务代码中来解决,使用复杂存储过来处理业务逻辑的情况不多见。MySQL官方默认关闭Query Cache主要还是因为Query Cache的性能局限性:
“Waiting on query cache mutex”这种错误是典型的使用Query Cache不当所引起的错误。由于Query Cache设计的暴力清除策略,导致只要有数据表进行写操作,Query Cache中和这个数据表相关的所有结果都要失效的现象。所有需要从Query Cache中读取相关数据的客户端session就要等待数据清除完毕,所以就会出现以上错误提示。
如果这时query_cache_size设置得过大,反而会加剧这个问题的严重程度。因为过大的Query Cache区域意味着可能存储了和这个被写操作关联的数据表的更多查询结果集,也就需要更多时间去清除数据。
如果这张数据表又是写密集度非常高的数据表,那么这个问题会更加严重。因为Query Cache中相关数据会被频繁的擦除、重写。客户端session也会不停的进入锁定等待状态。
在实际业务应用中,笔者并不建议直接关闭Query Cache。而是建议在将query_cache_type参数设置为2(DEMAND)并分配不大的内存总空间(query_cache_size 设置为16MB足够了)的前提下,由业务层代码显式控制Query Cache的使用。