關於MySQL的查詢緩存

原理QueryCache(下面簡稱QC)是根據SQL語句來cache的。一個SQL查詢若是以select開頭,那麼MySQL服務器將嘗試對其使用 QC。每一個Cache都是以SQL文本做爲key來存的。在應用QC以前,SQL文本不會被做任何處理。也就是說,兩個SQL語句,只要相差哪怕是一個字符(例如大小寫不同;多一個空格等),那麼這兩個SQL將使用不一樣的一個CACHE。 不過SQL文本有可能會被客戶端作一些處理。例如在官方的命令行客戶端裏,在發送SQL給服務器以前,會作以下處理: 過濾全部註釋 去掉SQL文本先後的空格,TAB等字符。注意,是文本前面和後面的。中間的不會被去掉。 下面的三條SQL裏,由於SELECT大小寫的關係,最後一條和其餘兩條在QC裏確定是用的不同的存儲位置。而第一條和第二條,區別在於後者有個註釋,在不一樣客戶端,會有不同的結果。因此,保險起見,請儘可能不要使用動態的註釋。在PHP的mysql擴展裏,SQL的註釋是不會被去掉的。也就是三條 SQL會被存儲在三個不一樣的緩存裏,雖然它們的結果都是同樣的。 select * FROM people where name='surfchen'; select * FROM people where /*hey~*/name='surfchen'; SELECT * FROM people where name='surfchen'; 目前只有select語句會被cache,其餘相似show,use的語句則不會被cache。 由於QC是如此前端,如此簡單的一個緩存系統,因此若是一個表被更新,那麼和這個表相關的SQL的全部QC都會被失效。假設一個聯合查詢裏涉及到了表A和表B,若是表A或者表B的其中一個被更新(update或者delete),這個查詢的QC將會失效。 也就是說,若是一個表被頻繁更新,那麼就要考慮清楚到底是否應該對相關的一些SQL進行QC了。一個被頻繁更新的表若是被應用了QC,可能會加劇數據庫的負擔,而不是減輕負擔。我通常的作法是默認打開QC,而對一些涉及頻繁更新的表的SQL語句加上SQL_NO_CACHE關鍵詞來對其禁用CACHE。這樣能夠儘量避免沒必要要的內存操做,儘量保持內存的連續性。 那些查詢很分散的SQL語句,也不該該使用QC。例如用來查詢用戶和密碼的語句——「select pass from user where name='surfchen'」。這樣的語句,在一個系統裏,頗有可能只在一個用戶登錄的時候被使用。每一個用戶的登錄所用到的查詢,都是不同的SQL 文本,QC在這裏就幾乎不起做用了,由於緩存的數據幾乎是不會被用到的,它們只會在內存裏佔地方。 存儲塊 在本節裏「存儲塊」和「block」是同一個意思 QC 緩存一個查詢結果的時候,通常狀況下不是一次性地分配足夠多的內存來緩存結果的。而是在查詢結果得到的過程當中,逐塊存儲。當一個存儲塊被填滿以後,一個新的存儲塊將會被建立,並分配內存(allocate)。單個存儲塊的內存分配大小經過query_cache_min_res_unit參數控制,默認爲 4KB。最後一個存儲塊,若是不能被所有利用,那麼沒使用的內存將會被釋放。若是被緩存的結果很大,那麼會可能會致使分配內存操做太頻繁,系統系能也隨之降低;而若是被緩存的結果都很小,那麼可能會致使內存碎片過多,這些碎片若是過小,就頗有可能不能再被分配使用。 除了查詢結果須要存儲塊以外,每一個SQL文本也須要一個存儲塊,而涉及到的表也須要一個存儲塊(表的存儲塊是全部線程共享的,每一個表只須要一個存儲塊)。存儲塊總數量=查詢結果數量*2+涉及的數據庫表數量。也就是說,第一個緩存生成的時候,至少須要三個存儲塊:表信息存儲塊,SQL文本存儲塊,查詢結果存儲塊。而第二個查詢若是用的是同一個表,那麼最少只須要兩個存儲塊:SQL文本存儲塊,查詢結果存儲塊。 經過觀察 Qcache_queries_in_cache和Qcache_total_blocks能夠知道平均每一個緩存結果佔用的存儲塊。它們的比例若是接近 1:2,則說明當前的query_cache_min_res_unit參數已經足夠大了。若是Qcache_total_blocks比 Qcache_queries_in_cache多不少,則須要增長query_cache_min_res_unit的大小。 Qcache_queries_in_cache*query_cache_min_res_unit(sql 文本和表信息所在的block佔用的內存很小,能夠忽略)若是遠遠大於query_cache_size-Qcache_free_memory,那麼能夠嘗試減少 query_cache_min_res_unit的值。 調整大小 若是Qcache_lowmem_prunes增加迅速,意味着不少緩存由於內存不夠而被釋放,而不是由於相關表被更新。嘗試加大query_cache_size,儘可能使Qcache_lowmem_prunes零增加。 啓動參數 show variables like 'query_cache%'能夠看到這些信息。 query_cache_limit:若是單個查詢結果大於這個值,則不Cache query_cache_size: 分配給QC的內存。若是設爲0,則至關於禁用QC。要注意QC必須使用大約40KB來存儲它的結構,若是設定小於 40KB,則至關於禁用QC。QC存儲的最小單位是1024 byte,因此若是你設定了一個不是1024的倍數的值,這個值會被四捨五入到最接近當前值的等於1024的倍數的值。 query_cache_type:0 徹底禁止QC,不受SQL語句控制(另外可能要注意的是,即便這裏禁用,上面一個參數所設定的內存大小仍是會被分配);1啓用QC,能夠在SQL語句使用 SQL_NO_CACHE禁用;2能夠在SQL語句使用SQL_CACHE啓用。 query_cache_min_res_unit:每次給QC結果分配內存的大小 狀態 show status like 'Qcache%'能夠看到這些信息。 Qcache_free_blocks: 當一個表被更新以後,和它相關的cache blocks將被free。可是這個block依然可能存在隊列中,除非是在隊列的尾部。這些blocks將會被統計到這個值來。能夠用FLUSH QUERY CACHE語句來清空free blocks。 Qcache_free_memory:可用內存,若是很小,考慮增長query_cache_size Qcache_hits:自mysql進程啓動起,cache的命中數量 Qcache_inserts:自mysql進程啓動起,被增長進QC的數量 Qcache_lowmem_prunes:因爲內存過少而致使QC被刪除的條數。加大query_cache_size,儘量保持這個值0增加。 Qcache_not_cached:自mysql進程啓動起,沒有被cache的只讀查詢數量(包括select,show,use,desc等) Qcache_queries_in_cache:當前被cache的SQL數量 Qcache_total_blocks: 在QC中的blocks數。一個query可能被多個blocks存儲,而這幾個blocks中的最後一個,未用滿的內存將會被釋放掉。例如一個QC結果要佔6KB內存,若是query_cache_min_res_unit是4KB,則最後將會生成3個 blocks,第一個block用來存儲sql語句文本,這個不會被統計到query+cache_size裏,第二個block爲4KB,第三個 block爲2KB(先allocate4KB,而後釋放多餘的2KB)。每一個表,當第一個和它有關的SQL查詢被CACHE的時候,會使用一個 block來存儲表信息。也就是說,block會被用在三處地方:表信息,SQL文本,查詢結果。 另一篇: 若是 MySQL Server 負載比較高,處理很是繁忙的話,能夠啓動Query Cache 以加速響應時間,啓動方法能夠在my.cnf(Linux)或my.ini(Windows)中加入不如下項目:(Redhat下面是:/etc /my.cnf;Debian和Ubuntu是在/etc/mysql/my.cnf) query_cache_size = 268435456 query_cache_type = 1 query_cache_limit = 1048576 以上語句的設置中 query_cache_size 是分配256M內存給Query Cache;query_cache_type=1,是給全部的查詢作Cache;query_cache_limit 是指定個別的查詢語句1MB的內存。 這些數據能夠根據本身的需求做出適當的更改,設置完成以後,保存文檔,從新啓動MySQL便可。 query_cache_type 0 表明不使用緩衝, 1 表明使用緩衝,2 表明根據須要使用。 設置 1 表明緩衝永遠有效,若是不須要緩衝,就須要使用以下語句: SELECT SQL_NO_CACHE * FROM my_table WHERE ... 若是設置爲 2 ,須要開啓緩衝,能夠用以下語句: SELECT SQL_CACHE * FROM my_table WHERE ... 用 SHOW STATUS 能夠查看緩衝的狀況: mysql> show status like 'Qca%'; +-------------------------+----------+ | Variable_name | Value | +-------------------------+----------+ | Qcache_queries_in_cache | 8 | | Qcache_inserts | 545875 | | Qcache_hits | 83951 | | Qcache_lowmem_prunes | 0 | | Qcache_not_cached | 2343256 | | Qcache_free_memory | 33508248 | | Qcache_free_blocks | 1 | | Qcache_total_blocks | 18 | +-------------------------+----------+ 8 rows in set (0.00 sec) 若是須要計算命中率,須要知道服務器執行了多少 SELECT 語句: mysql> show status like 'Com_sel%'; +---------------+---------+ | Variable_name | Value | +---------------+---------+ | Com_select | 2889628 | +---------------+---------+ 1 row in set (0.01 sec) 在本例中, MySQL 命中了 2,889,628 條查詢中的 83,951 條,並且 INSERT 語句只有 545,875 條。所以,它們二者的和和280萬的總查詢相比有很大差距,所以,咱們知道本例使用的緩衝類型是 2 。 而在類型是 1 的例子中, Qcache_hits 的數值會遠遠大於 Com_select 。
相關文章
相關標籤/搜索