MariaDB—— 13.查询缓存

“查询缓存”,顾名思义,就是将查询的结果缓存下载,如果查询语句完全相同,则直接返回缓存中的结果。
如果应用程序在某个场景中,需要经常执行大量的相同的查询,而且查询出的数据不会经常被更新,那么,使用查询缓存会有一定的性能提升。

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]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章