1 原理
MySQL查詢緩存保存查詢返回的完整結果。當查詢命中該緩存,會馬上返回結果,跳過了解析,優化和執行階段。
查詢緩存會跟蹤查詢中涉及的每一個表,若是這寫表發生變化,那麼和這個表相關的全部緩存都將失效。
可是隨着服務器功能的強大,查詢緩存也可能成爲整個服務器的資源競爭單點。
2 初步設置
默認這個開關是關閉的,就是禁止使用query_cache,查詢是否使用語句以下:
mysql> SHOW VARIABLES LIKE 'have_query_cache';
Variable_name | Value |
+------------------+-------+
| have_query_cache | YES |
注意這個只是顯示,支持query_cache功能而已,默認是關閉的,經過這個語句
查詢設置狀況:
mysql> SHOW STATUS LIKE 'Qcache%';
如發現結果中query_cache_size =0,則沒設置,設置的方法爲在
my.ini中,設置
query_cache_size=128M
增長一行:query_cache_type=1
3 MYSQL如何分配query_cache_size
mySQL用於查詢的緩存的內存被分紅一個個變長數據塊,用來存儲類型,大小,數據等信息。
當服務器啓動的時候,會初始化緩存須要的內存,是一個完整的空閒塊。當查詢結果須要緩存的時候,先從空閒塊中申請一個數據塊大於參數query_cache_min_res_unit的配置,即便緩存數據很小,申請數據塊也是這個,由於查詢開始返回結果的時候就分配空間,此時沒法預知結果多大。
分配內存塊須要先鎖住空間塊,因此操做很慢,MySQL會盡可能避免這個操做,選擇儘量小的內存塊,若是不夠,繼續申請,若是存儲完時有空餘則釋放多餘的。
4 如何判斷是否命中
緩存存放在一個引用表中,經過一個哈希值引用,這個哈希值包括查詢自己,數據庫,客戶端協議的版本等,任何字符上的不一樣,例如空格,註釋都會致使緩存不命中。
當查詢中有一些不肯定的數據時,是不會緩存的,比方說now(),current_date(),自定義函數,存儲函數,用戶變量,字查詢等。因此這樣的查詢也就不會命中緩存,可是還會去檢測緩存的,由於查詢緩存在解析SQL以前,因此MySQL並不知道查詢中是否包含該類函數,只是不緩存,天然不會命中。
具體概括以下:
BENCHMARK()
CONNECTION_ID()
CURDATE()
CURRENT_DATE()
CURRENT_TIME()
CURRENT_TIMESTAMP()
CURTIME()
DATABASE()
帶一個參數的ENCRYPT()
FOUND_ROWS()
GET_LOCK()
LAST_INSERT_ID()
LOAD_FILE()
MASTER_POS_WAIT()
NOW()
RAND()
RELEASE_LOCK()
SYSDATE()
不帶參數的UNIX_TIMESTAMP()
USER()
· 引用自定義函數(UDFs)。
· 引用自定義變量。
· 引用mysql系統數據庫中的表。
· 下面方式中的任何一種:
SELECT ...IN SHARE MODE
SELECT ...FOR UPDATE
SELECT ...INTO OUTFILE ...
SELECT ...INTO DUMPFILE ...
SELECT * FROM ...WHERE autoincrement_col IS NULL
· 被做爲編寫好的語句,即便沒有使用佔位符。例如,下面使用的查詢:
char *my_sql_stmt = "SELECT a,b FROM table_c";
/* ...*/
mysql_stmt_prepare(stmt,my_sql_stmt,strlen(my_sql_stmt));
不被緩存。
· 使用TEMPORARY表。
· 不使用任何表。
· 用戶有某個表的列級別權限。
打開Qcache對讀和寫都會帶來額外的消耗:
a、讀查詢開始以前必須檢查是否命中緩存。
b、若是讀查詢能夠緩存,那麼執行完以後會寫入緩存。
c、當向某個表寫入數據的時候,必須將這個表全部的緩存設置爲失效,若是緩存空間很大,則消耗也會很大,可能使系統僵死一段時間,由於這個操做是靠全局鎖操做來保護的。
對InnoDB表,當修改一個表時,設置了緩存失效,可是多版本特性會暫時將這修改對其餘事務屏蔽,在這個事務提交以前,全部查詢都沒法使用緩存,直到這個事務被提交,因此長時間的事務,會大大下降查詢緩存的命中
一個表能夠被許多類型的語句更改,例如INSERT、UPDATE、DELETE、TRUNCATE、ALTER TABLE、DROP TABLE或DROP DATABASE。
對於InnoDB而言,事物的一些特性還會限制查詢緩存的使用。當在事物A中修改了B表時,由於在事物提交以前,對B表的修改對其餘的事物而言是不可見的。爲了保證緩存結果的正確性,InnoDB採起的措施讓全部涉及到該B表的查詢在事物A提交以前是不可緩存的。若是A事物長時間運行,會嚴重影響查詢緩存的命中率
查詢緩存的空間不要設置的太大。
由於查詢緩存是靠一個全局鎖操做保護的,若是查詢緩存配置的內存比較大且裏面存放了大量的查詢結果,當查詢緩存失效的時候,會長時間的持有這個全局鎖。由於查詢緩存的命中檢測操做以及緩存失效檢測也都依賴這個全局鎖,因此可能會致使系統僵死的狀況
5 具體參數含義:
show status like ‘%Qcache%’;
Variable_name | Value |
+————————-+———–+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 134208800 |
| Qcache_hits | 0 |
| Qcache_inserts | 0 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 2 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 1 |
解析:
Qcache_free_blocks:表示查詢緩存中目前還有多少剩餘的blocks,若是該值顯示較大,則說明查詢緩存中的內存碎片過多了,可能在必定的時間進行整理。
減小碎片:
合適的query_cache_min_res_unit能夠減小碎片,這個參數最合適的大小和應用程序查詢結果的平均大小直接相關,能夠經過內存實際消耗(query_cache_size - Qcache_free_memory)除以Qcache_queries_in_cache計算平均緩存大小。
能夠經過Qcache_free_blocks來觀察碎片,這個值反應了剩餘的空閒塊,若是這個值不少,可是
Qcache_lowmem_prunes卻不斷增長,則說明碎片太多了。可使用flush query cache整理碎片,從新排序,但不會清空,清空命令是reset query cache。整理碎片期間,查詢緩存沒法被訪問,可能致使服務器僵死一段時間,因此查詢緩存不宜太大。
Qcache_free_memory:查詢緩存的內存大小,經過這個參數能夠很清晰的知道當前系統的查詢內存是否夠用,是多了,仍是不夠用,DBA能夠根據實際狀況作出調整。
Qcache_hits:表示有多少次命中緩存。咱們主要能夠經過該值來驗證咱們的查詢緩存的效果。數字越大,緩存效果越理想。
Qcache_inserts: 表示多少次未命中而後插入,意思是新來的SQL請求在緩存中未找到,不得不執行查詢處理,執行查詢處理後把結果insert到查詢緩存中。這樣的狀況的次 數,次數越多,表示查詢緩存應用到的比較少,效果也就不理想。固然系統剛啓動後,查詢緩存是空的,
這很正常。
Qcache_lowmem_prunes:該參數記錄有多少條查詢由於內存不足而被移除出查詢緩存。經過這個值,用戶能夠適當的調整緩存大小。
Qcache_not_cached: 表示由於query_cache_type的設置而沒有被緩存的查詢數量。
Qcache_queries_in_cache:當前緩存中緩存的查詢數量。
Qcache_total_blocks:當前緩存的block數量。
提升查詢緩存的使用率:
若是碎片不是問題,命中率卻很是低,多是內存不足,能夠經過 Qcache_free_memory 參數來查看沒有使用的內存。
若是2者都沒有問題,命中率依然很低,那麼說明緩存不適合你的當前系統。能夠經過設置
query_cache_size = 0或者query_cache_type 來關閉查詢緩存。
-------------------------------------------------------------
下面講解 show variables like '%query_cache%'時的參數
query_cache_limit:容許 Cache 的單條 Query 結果集的最大容量,默認是1MB,超過此參數設置的 Query 結果集將不會被 Cache
query_cache_min_res_unit:設置 Query Cache 中每次分配內存的最小空間大小,也就是每一個 Query 的 Cache 最小佔用的內存空間大小
query_cache_size:設置 Query Cache 所使用的內存大小,默認值爲0,大小必須是1024的整數倍,若是不是整數倍,MySQL 會自動調整下降最小量以達到1024的倍數
query_cache_type:控制 Query Cache 功能的開關,能夠設置爲0(OFF),1(ON)和2(DEMAND)三種,意義分別以下:
0(OFF):關閉 Query Cache 功能,任何狀況下都不會使用 Query Cache
1(ON):開啓 Query Cache 功能,可是當 SELECT 語句中使用的 SQL_NO_CACHE 提示後,將不使用Query Cache
2(DEMAND):開啓 Query Cache 功能,可是隻有當 SELECT 語句中使用了 SQL_CACHE 提示後,才使用 Query Cache
query_cache_wlock_invalidate:控制當有寫鎖定發生在表上的時刻是否先失效該表相關的 Query Cache,若是設置爲 1(TRUE),則在寫鎖定的同時將失效該表相關的全部 Query Cache,若是設置爲0(FALSE)則在鎖定時刻仍然容許讀取該表相關的 Query Cache。
相關問答:
Query Cache 如何處理子查詢的?
這是我遇到的最爲常見的一個問題。其實 Query Cache 是以客戶端請求提交的 Query 爲對象來處理的,只要客戶端請求的是一個 Query,不管這個 Query 是一個簡單的單表查詢仍是多表 Join,亦或者是帶有子查詢的複雜 SQL,都被看成成一個 Query,不會被分拆成多個 Query 來進行 Cache。因此,存在子查詢的複雜 Query 也只會產生一個Cache對象,子查詢不會產生單獨的Cache內容。UNION[ALL] 類型的語句也一樣如此。
Query Cache 是以 block 的方式存儲的數據塊嗎?
不是,Query Cache 中緩存的內容僅僅只包含該 Query 所須要的結果數據,是結果集。固然,並不只僅只是結果數據,還包含與該結果相關的其餘信息,好比產生該 Cache 的客戶端鏈接的字符集,數據的字符集,客戶端鏈接的 Default Database等。
Query Cache 爲何效率會很是高,即便全部數據均可以 Cache 進內存的狀況下,有些時候也不如使用 Query Cache 的效率高?
Query Cache 的查找,是在 MySQL 接受到客戶端請求後在對 Query 進行權限驗證以後,SQL 解析以前。也就是說,當 MySQL 接受到客戶端的SQL後,僅僅只須要對其進行相應的權限驗證後就會經過 Query Cache 來查找結果,甚至都不須要通過 Optimizer 模塊進行執行計劃的分析優化,更不準要發生任何存儲引擎的交互,減小了大量的磁盤 IO 和 CPU 運算,因此效率很是高。
客戶端提交的 SQL 語句大小寫對 Query Cache 有影響嗎?
有,因爲 Query Cache 在內存中是以 HASH 結構來進行映射,HASH 算法基礎就是組成 SQL 語句的字符,因此必需要整個 SQL 語句在字符級別徹底一致,才能在 Query Cache 中命中,即便多一個空格也不行。
一個 SQL 語句在 Query Cache 中的內容,在什麼狀況下會失效?
爲了保證 Query Cache 中的內容與是實際數據絕對一致,當表中的數據有任何變化,包括新增,修改,刪除等,都會使全部引用到該表的 SQL 的 Query Cache 失效。
爲何個人系統在開啓了 Query Cache 以後總體性能反而降低了?
當開啓了 Query Cache 以後,尤爲是當咱們的 query_cache_type 參數設置爲 1 之後,MySQL 會對每一個 SELECT 語句都進行 Query Cache 查找,查找操做雖然比較簡單,但仍然也是要消耗一些 CPU 運算資源的。而因爲 Query Cache 的失效機制的特性,可能因爲表上的數據變化比較頻繁,大量的 Query Cache 頻繁的被失效,因此 Query Cache 的命中率就可能比較低下。因此有些場景下,Query Cache 不只不能提升效率,反而可能形成負面影響。
如何確認一個系統的 Query Cache 的運行是否健康,命中率如何,設置量是否足夠?
MySQL 提供了一系列的 Global Status 來記錄 Query Cache 的當前狀態,具體以下:
Qcache_free_blocks:目前還處於空閒狀態的 Query Cache 中內存 Block 數目
Qcache_free_memory:目前還處於空閒狀態的 Query Cache 內存總量
Qcache_hits:Query Cache 命中次數
Qcache_inserts:向 Query Cache 中插入新的 Query Cache 的次數,也就是沒有命中的次數
Qcache_lowmem_prunes:當 Query Cache 內存容量不夠,須要從中刪除老的 Query Cache 以給新的 Cache 對象使用的次數
Qcache_not_cached:沒有被 Cache 的 SQL 數,包括沒法被 Cache 的 SQL 以及因爲 query_cache_type 設置的不會被 Cache 的 SQL
Qcache_queries_in_cache:目前在 Query Cache 中的 SQL 數量
Qcache_total_blocks:Query Cache 中總的 Block 數量
能夠根據這幾個狀態計算出 Cache 命中率,計算出 Query Cache 大小設置是否足夠,總的來講,我我的不建議將 Query Cache 的大小設置超過256MB,這也是業界比較經常使用的作法。
MySQL Cluster 是否可使用 Query Cache?
其實在咱們的生產環境中也沒有使用 MySQL Cluster,因此我也沒有在 MySQL Cluster 環境中使用 Query Cache 的實際經驗,只是 MySQL 文檔中說明確實能夠在 MySQL Cluster 中使用 Query Cache。從 MySQL Cluster 的原理來分析,也以爲應該可使用,畢竟 SQL 節點和數據節點比較獨立,各司其職,只是 Cache 的失效機制會要稍微複雜一點。mysql