MySQL的Query Cache原理分析
2024-07-24 12:44:08
供稿:網友
原理
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。最后一個存儲塊,如果不能被全部利用,那么沒使用的內存將會被釋放。如果被緩存的結果很大,那么會可能會導致分配內存操作太頻繁,系統系能也隨之下降;而如果被緩存的結果都很小,那么可能會導致內存碎片過多,這些碎片如果太小,就很有可能不能再被分配使用。