mysql查詢緩存

一:緩存條件,原理

MySQL Query Cache是用來緩存我們所執行的SELECT語句以及該語句的結果集,MySql在實現Query Cache的具體技術細節上類似典型的KV存儲,就是將SELECT語句和該查詢語句的結果集做了一個HASH映射並保存在一定的內存區域中。當客戶端發起SQL查詢時,Query Cache的查找邏輯是,先對SQL進行相應的權限驗證,接着就通過Query Cache來查找結果(注意必須是完全相同,即使多一個空格或者大小寫不 同都認爲不同,即使完全相同的SQL,如果使用不同的字符集、不同的協議等也會被認爲是不同的查詢而分別進行緩存)。它不需要經過Optimizer模塊進行執行計劃的分析優化,更不需要發生同任何存儲引擎的交互,減少了大量的磁盤IO和CPU運 算,所以有時候效率非常高。

查詢緩存的工作流程如下:

1:命中條件

緩存存在一個hash表中,通過查詢SQL,查詢數據庫,客戶端協議等作爲key.在判斷是否命中前,MySQL不會解析SQL,而是直接使用SQL去查詢緩存,SQL任何字符上的不同,如空格,註釋,都會導致緩存不命中.

如果查詢中有不確定數據,例如CURRENT_DATE()和NOW()函數,那麼查詢完畢後則不會被緩存.所以,包含不確定數據的查詢是肯定不會找到可用緩存的

2:工作流程
  1. 服務器接收SQL,以SQL和一些其他條件爲key查找緩存表(額外性能消耗)
  2. 如果找到了緩存,則直接返回緩存(性能提升)
  3. 如果沒有找到緩存,則執行SQL查詢,包括原來的SQL解析,優化等
  4. 執行完SQL查詢結果以後,將SQL查詢結果存入緩存表(額外性能消耗)

二:緩存參數

1:查看當前查詢緩存相關參數狀態:

SHOW VARIABLES LIKE '%query_cache%';

查詢結果

2:緩存配置參數解釋

1. query_cache_type: 查詢緩存類型,是否打開緩存

可選項

  a、0(OFF):關閉 Query Cache 功能,任何情況下都不會使用 Query Cache;
  b、1(ON):開啓 Query Cache 功能,但是當SELECT語句中使用SQL_NO_CACHE提示後,將不使用Query Cache;
  c、2(DEMAND):開啓Query Cache 功能,但是隻有當SELECT語句中使用了SQL_CACHE 提示後,才使用Query Cache。

備註1:

如果query_cache_type爲on而又不想利用查詢緩存中的數據,可以用下面的SQL:

SELECT SQL_NO_CACHE * FROM my_table WHERE condition;

如果值爲2,要使用緩存的話,需要使用SQL_CACHE開關參數:

SELECT SQL_CACHE * FROM my_table WHERE condition;

`

這裏我遇到的情況: 1、如果事先查詢緩存是關閉的然而用 set @@global.query_cache_type=1; 會報錯

ERROR 1651 (HY000): Query cache is disabled; restart the server with
query_cache_type=1 to enable it

2、如果事先是打開着的嘗試去閉關它,那麼這個關閉也是不完全的,這種情況下查詢還是會去嘗試查找緩存。

最好的關閉查詢緩存的辦法就是把my.cnf 中的query_cache_type=0然後再重啓mysql。

2. query_cache_size: 緩存使用的總內存空間大小,單位是字節,這個值必須是1024的整數倍,否則MySQL 會自動調整降低最小量以達到1024的倍數;(感覺這個應該跟文件系統的blcok大小有關)
3. query_cache_min_res_unit: 分配內存塊時的最小單位大小,設置查詢緩存Query Cache每次分配內存的最小空間大小,即每個查詢的緩存最小佔用的內存空間大小;
4. query_cache_limit: 允許緩存的單條查詢結果集的最大容量,默認是1MB,超過此參數設置的查詢結果集將不會被緩存;
5. query_cache_wlock_invalidate: 如果某個數據表被鎖住,是否仍然從緩存中返回數據,默認是OFF,表示仍然可以返回

控制當有寫鎖定發生在表上的時刻是否先失效該表相關的Query Cache,如果設置爲 1(TRUE),則在寫鎖定的同時將失效該表相關的所有Query Cache,如果設置爲0(FALSE)則在鎖定時刻仍然允許讀取該表相關的Query Cache。

GLOBAL STAUS 中 關於 緩存的參數解釋:
Qcache_free_blocks: 緩存池中空閒塊的個數
Qcache_free_memory: 緩存中空閒內存量
Qcache_hits: 緩存命中次數
Qcache_inserts: 緩存寫入次數
Qcache_lowmen_prunes: 因內存不足刪除緩存次數
Qcache_not_cached: 查詢未被緩存次數,例如查詢結果超出緩存塊大小,查詢中包含可變函數等
Qcache_queries_in_cache: 當前緩存中緩存的SQL數量
Qcache_total_blocks: 緩存總block數

3:設置配置參數:

SET GLOBAL query_cache_size = 134217728;
4:查看緩存命中次數(是個累加值):
SHOW STATUS LIKE 'Qcache_hits';

三:緩存數據失效時機

1:在表的結構或數據發生改變時,查詢緩存中的數據不再有效。有這些INSERT、UPDATE、 DELETE、TRUNCATE、ALTER TABLE、DROP TABLE或DROP DATABASE會導致緩存數據失效。所以查詢緩存適合有大量相同查詢的應用,不適合有大量數據更新的應用。
當某個表正在寫入數據,則這個表的緩存(命中檢查,緩存寫入等)將會處於失效狀態.在Innodb中,如果某個事務修改了表,則這個表的緩存在事務提交前都會處於失效狀態,在這個事務提交前,這個表的相關查詢都無法被緩存.

2:清理查詢緩存 & 減少碎片策略

清理查詢緩存內存碎片

 FLUSH QUERY_CACHE;

從查詢緩存中移出所有查詢

 RESET QUERY_CACHE;

關閉所有打開的表,同時該操作將會清空查詢緩存中的內容

 FLUSH TABLES;
  1. 選擇合適的block大小
  2. 使用 FLUSH QUERY CACHE 命令整理碎片.這個命令在整理緩存期間,會導致其他連接無法使用查詢緩存

PS: 清空緩存的命令式 RESET QUERY CACHE

四:緩存的內存管理

緩存會在內存中開闢一塊內存(query_cache_size)來維護緩存數據,其中有大概40K的空間是用來維護緩存的元數據的(什麼是元數據:http://www.cnblogs.com/Alight/p/3982086.html),例如空間內存,數據表和查詢結果的映射,SQL和查詢結果的映射等.

MySQL將這個大內存塊分爲小的內存塊(query_cache_min_res_unit),每個小塊中存儲自身的類型,大小和查詢結果數據,還有指向前後內存塊的指針.

MySQL需要設置單個小存儲塊的大小,在SQL查詢開始(還未得到結果)時就去申請一塊空間,所以即使你的緩存數據沒有達到這個大小,也需要用這 個大小的數據塊去存(這點跟Linux文件系統的Block一樣).如果結果超出這個內存塊的大小,則需要再去申請一個內存塊.當查詢完成發現申請的內存 塊有富餘,則會將富餘的空間釋放掉,這就會造成內存碎片問題,見下圖
在這裏插入圖片描述
此處查詢1和查詢2之間的空白部分就是內存碎片,這部分空閒內存是有查詢1查詢完以後釋放的,假設這個空間大小小於MySQL設定的內存塊大小,則無法再被使用,造成碎片問題
在查詢開始時申請分配內存Block需要鎖住整個空閒內存區,所以分配內存塊是非常消耗資源的.注意這裏所說的分配內存是在MySQL初始化時就開闢的那塊內存上分配的

五:緩存的使用時機 & 性能

衡量打開緩存是否對系統有性能提升是一個很難的話題

  1. 通過緩存命中率判斷, 緩存命中率 = 緩存命中次數 (Qcache_hits) / 查詢次數 (Com_select)
  2. 通過緩存寫入率, 寫入率 = 緩存寫入次數 (Qcache_inserts) / 查詢次數 (Qcache_inserts)
  3. 通過 命中-寫入率 判斷, 比率 = 命中次數 (Qcache_hits) / 寫入次數 (Qcache_inserts), 高性能MySQL中稱之爲比較能反映性能提升的指數,一般來說達到3:1則算是查詢緩存有效,而最好能夠達到10:1

任何事情過猶不及,尤其對於某些寫頻繁的系統,開啓Query Cache功能可能並不能讓系統性能有提升,有時反而會有下降。原因是MySql爲了保證Query Cache緩存的內容和實際數據絕對一致,當某個數據表發生了更新、刪除及插入操作,MySql都會強制使所有引用到該表的查詢SQL的Query Cache失效。對於密集寫操作,啓用查詢緩存後很可能造成頻繁的緩存失效,間接引發內存激增及CPU飆升,對已經非常忙碌的數據庫系統這是一種極大的負擔。

六:查詢緩存問題分析

在這裏插入圖片描述

七:InnoDB與查詢緩存

Innodb會對每個表設置一個事務計數器,裏面存儲當前最大的事務ID.當一個事務提交時,InnoDB會使用MVCC中系統事務ID最大的事務ID跟新當前表的計數器.

只有比這個最大ID大的事務能使用查詢緩存,其他比這個ID小的事務則不能使用查詢緩存.

另外,在InnoDB中,所有有加鎖操作的事務都不使用任何查詢緩存

八、其他

Query Cache因MySql的存儲引擎不同而實現略有差異,比如MyISAM,緩存的結果集存儲在OS Cache中,而最流行的InnoDB則放在Buffer Pool中。

參考:https://www.cnblogs.com/Alight/p/3981999.html

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