“查询缓存”,顾名思义,就是将查询的结果缓存下载,如果查询语句完全相同,则直接返回缓存中的结果。
如果应用程序在某个场景中,需要经常执行大量的相同的查询,而且查询出的数据不会经常被更新,那么,使用查询缓存会有一定的性能提升。
MariaDB [mysql]> show variables like '%query%';
+------------------------------+-----------------+
| Variable_name | Value |
+------------------------------+-----------------+
| expensive_subquery_limit | 100 |
| ft_query_expansion_limit | 20 |
| have_query_cache | YES |
| long_query_time | 10.000000 |
| query_alloc_block_size | 16384 |
| query_cache_limit | 1048576 |
| query_cache_min_res_unit | 4096 |
| query_cache_size | 1048576 |
| query_cache_strip_comments | OFF |
| query_cache_type | OFF |
| query_cache_wlock_invalidate | OFF |
| query_prealloc_size | 24576 |
| slow_query_log | OFF |
| slow_query_log_file | master-slow.log |
+------------------------------+-----------------+
query_cache_type的值可以设置为:ON、OFF、DEMAND,分别表示已启用、已禁用、按需缓存,设置在my.cnf中即可。
have_query_cache的值为yes,表示当前数据库支持缓存功能
query_cache_limit 表示单条查询缓存的最大值,如果查询结果超过此值的大小,即使指定缓存当前结果,结果也不会被缓存,默认值为1M。
query_cache_min_res_unit表示缓存存储于内存的最小单元,默认为4k,也就是说,即使查询结果只有1k,也会占用4k内存,所以,如果此值设置的过大,会造成内存空间的浪费,如果此值设置的过小,则会频繁的分配内存单元或者频繁的回收内存单元。
query_cache_size 表示查询缓存的总大小,也就是说,内存中用于查询缓存的空间大小,如果其值为0,即使开启了查询缓存,也无法缓存,上图中,即为这种情况。
query_cache_wlock_invalidate 表示查询语句所查询的表如果被写锁锁定,是否仍然使用缓存返回结果。
如果某张表中的数据变化频繁,而在查询这张表的内容时又使用了缓存,那么缓存失效的频率将会非常高,而且计算查询语句的hash值也是需 要消耗资源的,当并发查询量大时,则需要考虑这些因素。综上所述,往往在数据变化不频繁、且又需要重复执行相同查询的场景中使用缓存。因为mysql收到查询请求时,会对查询语句进行hash计算,计算出其对应的hash值,通过这个hash值查找是否存在对应的缓存,所 以,即使查询语句的大小写不同,也会被认为是不同的查询语句,如果当前hash码没有命中对应的缓存,mysql则会将对应的hash值存放在对应的 hash表中,同时将查询结果存放在对应的缓存中,如果查询语句的hash值命中了对应缓存项,则直接从缓存中返回响应的查询结果,如果缓存对应的表中的 数据发生了变化,那么查询缓存中,所有与变化的数据表有关的缓存都将失效,失效缓存对应的内存空间将被释放。
在开启缓存的时候(query_cache_type=ON),指定对应的查询语句不使用缓存:
MariaDB [(none)]> set query_cache_type='ON';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> select sql_no_cache host from mysql.user;
+-----------+
| host |
+-----------+
| % |
| 127.0.0.1 |
| ::1 |
| localhost |
| localhost |
| master |
+-----------+
6 rows in set (0.00 sec)
在按需使用缓存时(query_cache_type=DEMAND),指定对应的查询语句使用缓存:
MariaDB [(none)]> set query_cache_type='DEMAND';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> select sql_cache host from mysql.user;
+-----------+
| host |
+-----------+
| % |
| 127.0.0.1 |
| ::1 |
| localhost |
| localhost |
| master |
+-----------+
6 rows in set (0.00 sec)
将查询缓存设置为按需缓存,同时,设置缓存空间大小为100M。
MariaDB [(none)]> set query_cache_type='DEMAND';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> set global query_cache_size=100;
Query OK, 0 rows affected, 1 warning (0.00 sec)
使用如下语句查看缓存命中情况
MariaDB [(none)]> show status like 'Qcache%';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| Qcache_free_blocks | 0 |
| Qcache_free_memory | 0 |
| Qcache_hits | 0 |
| Qcache_inserts | 0 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 2 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 0 |
+-------------------------+-------+
8 rows in set (0.00 sec)
Qcache_queries_in_cache 表示已经缓存的SQL语句的数量,重复执行了3遍相同的查询语句,而且明确指定需要缓存,所以第一次执行就被缓存了。
Qcache_hits表示以被缓存的条目的命中次数,重复执行了3遍相同的查询语句,第一次被缓存,后两次被命中,所以此值为2。
Qcache_inserts表示在未命中缓存时,将查询结果写入缓存的次数,当第一次执行查询语句时,缓存中并没有对应缓存,所以第一次查询虽然未命中,但是会将查询结果写入缓存中一份。次值可以理解为未命中缓存,但是立即生成缓存的次数。
Qcache_lowmem_prunes 表示用于查询缓存的内存区域的修剪次数。
Qcache_not_cached 表示没有被缓存的查询语句的数量。
Qcache_free_memory表示查询缓存的空闲总量大小。
Qcache_free_blocks表示已分配的内存块中空闲块的数量。
Qcache_total_blocks表示当前查询缓存占用的内存的block数量。
通过上述统计信息的数值以及缓存设置相关的值,计算出查询缓存的相关指标,从而判断查询缓存是否对有一定的帮助,比如,通过上述数值计算出查询缓存的碎片率、缓存利用率、以及缓存命中率等信息。
查询缓存的碎片率 =(Qcache_free_blocks / Qcache_total_blocks)* 100%
查询缓存利用率 = (query_cache_size - Qcache_free_memory) / query_cache_size * 100%
查询缓存的命中率的计算需要查询出另一个参数的值,稍后描述,先说说上面两个。
从上述两个公式可以推断出,如果Qcache_free_blocks的值过大,则碎片率越高,证明缓存内存碎片略多,可以尝试适当的调小 query_cache_min_res_unit的值,也可以使用 FLUSH QUERY CACHE语句来清理缓存碎片。
如果查询缓存利用率太低,则表示query_cache_size设置的可能过大,可适度调小,如果缓存利用率非常高,同时Qcache_lowmem_prunes的值比较大,则表示query_cache_size的值设置的略小。
如果在调整query_cache_min_res_unit时不确定该调整为多大,可以使用如下公式计算出参考值。
query_cache_min_res_unit的预估值参考计算公式: (query_cache_size - Qcache_free_memory) / Qcache_queries_in_cache
如果想要计算查询缓存的命中率,可以使用如下公式(关于缓存命中率的计算存在争议,可以根据自己的理解与实际情况进行计算):
查询缓存命中率 = (Qcache_hits / Com_select)* 100%
上述公式中的Com_select表示查询语句的执行次数(这样描述并不准确),可以使用如下语句获得查询语句的执行次数
show status like “Com_select%”;
如果命中率长期保持较低的状态,则证明查询缓存功能对的帮助不是很大,可以考虑调整相关参数或者是关闭查询缓存功能。
使用 flush query cache,可以清理查询缓存碎片。
但是flush query cache;语句并不会从缓存中移出任何缓存,如果想要清除查询缓存中已经存在的缓存,可以使用如下语句
reset query cache;
reset query cache;语句会从查询缓存中移除所有查询结果的缓存。
————Blueicex 2020/3/28 19:45 [email protected]