MySQL中的Query Cache實現原理:將客戶端請求的Query語句(僅限於select類型的Query)通過一定的hash算法進行一個計算,得到一個hash值,存放在一個hash桶中,同時將該Query的結果集(Result Set)也存放在一個內存Cache中。存放Query hash值的鏈表中每一個hash值所在節點的同時,還存放了該Query所對應的 Result Set的Cache所在內存地址,以及該Query 涉及的所有 Table的標識等一些其他的信息。系統接收一個Query 時限計算出它的hash值到Query Cache中取匹配,找到了就直接將之前緩存的 Result Set返回,後端任何一條數據的發生變化,會通知Query Cache將所有與該Table有關的 Query的Cache全部失效,釋放占用的內存資源。個人感覺的和memcache的緩存差不多,只是比那個還方便,不用手工刪除緩存。呵呵~ 雖然Query Cache能帶來性能的提升,但它也有很多弊端:(1) Query語句的hash 運算及hash查找資源的消耗。 (2) Query Cache的失效問題。如果表中的數據變化頻繁,可能每次緩存到Query Cahce中的大 Cache 數據可能在被存入後很快因為表中的數據被改變而被清除,導致新的相同的 Query 進來後無法使用到之前的 Cache。 (3) Query Cache中緩存的是 Result Set ,而不是數據項,存在同一條記錄被 Cache 多次的可能性,從而造成內存資源的過渡消耗。
適度使用 Query Cahce 首先避免在查詢變化頻繁的 Table 的Query上使用,而應該在那些查詢頻率較低的 Table 的 Query上使用。MySQL中針對 Query Cahce有兩個專用的 SQL Hint(提示):SQL_NO_CACHE 和 SQL_CACHE,分別代表強制不適用 Query Cache 和強制使用 Query Cahce。
其次,對於那些變化非常少,大部分時候是靜態的數據。可以添加SQL_CACHE的SQL Hint 強制MySQL使用 Query Cache。
最後,有些SQL 的 Result Set 很大,如果使用 Query Cache 很容易造成 Cache內存不足 或者將之前一些老的 Cache 沖刷出去。解決辦法:使用 SQL_NO_CACHE 參數來強制它不適用 Query Cache; 另一種方法是通過設定“query_cache_limit”參數來控制 Query Cache中所緩存的最大 Result Set,系統默認為1M(1048576)。當某個 Query 的Result Set 大於"query_cache_limit"所設定的值時,Query Cache 是不會緩存這個Query的。
Query Cache 的相關系統參數變量和狀態變量執行:show variables like '%query_cache%' 得到Query Cache相關的系統參數變量:
"have_query_cache" : 該MySQL是否支持Query Cache
"query_cache_limit" :Query Cache存放的單個Query 最大 Result Set ,默認1M
"query_cache_min_res_unit":Query Cache每個Result Set 存放的最小內存大小,默認為4KB
"query_cache_size":系統中用於Query Cache內存的大小
"query_cache_type":系統是否打開了Query Cache的共能執行: show status like 'Qcache%'; 命令得到Query Cache相關的狀態變量。
"Qcache_free_blocks":Query Cache中目前還有多少剩余的blocks。如果該值顯示較大,則說明Query Cache中的內存碎片過多了,要進行整理。
"Qcache_free_memory":Query Cache中目前剩余內存大小。
“Qcache_hits”:多少次命中。
"Qcache_inserts":多少次未命中然後插入。
"Qcache_lowmem_prunes":多少條Query因為內存不足而被清除出Query Cache。
"Qcache_not_cached":因為query_cache_type的設置而不能被緩存(cache)的Query數量。
"Qcache_querIEs_in_cache":當前Query Cache中緩存緩存的Query 數量。
"Qcache_total_blocks":當前Query Cache中的block數量。