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]

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