在這個”Cache為王”的時代,我們總是通過不同的方式去緩存我們的結(jié)果從而提高響應(yīng)效率烫罩,但一個緩存機制是否有效惜傲,效果如何,卻是一個需要好好思考的問題贝攒。在MySQL中的Query Cache就是一個適用較少情況的緩存機制盗誊。在上圖中,如果緩存命中率非常高的話,有測試表明在極端情況下可以提高效率238%哈踱。但實際情況如何荒适?
Query Cache有如下規(guī)則,如果數(shù)據(jù)表被更改开镣,那么和這個數(shù)據(jù)表相關(guān)的全部Cache全部都會無效刀诬,并刪除之。這里“數(shù)據(jù)表更改”包括: INSERT, UPDATE, DELETE, TRUNCATE, ALTER TABLE, DROP TABLE, or DROP DATABASE等邪财。舉個例子陕壹,如果數(shù)據(jù)表posts訪問頻繁,那么意味著它的很多數(shù)據(jù)會被QC緩存起來树埠,但是每一次posts數(shù)據(jù)表的更新糠馆,無論更新是不是影響到了cache的數(shù)據(jù),都會將全部和posts表相關(guān)的cache清除怎憋。如果你的數(shù)據(jù)表更新頻繁的話榨惠,那么Query Cache將會成為系統(tǒng)的負(fù)擔(dān)。有實驗表明盛霎,糟糕時,QC會降低系統(tǒng)13%的處理能力耽装。
如果你的應(yīng)用對數(shù)據(jù)庫的更新很少愤炸,那么QC將會作用顯著。比較典型的如博客系統(tǒng)掉奄,一般博客更新相對較慢规个,數(shù)據(jù)表相對穩(wěn)定不變,這時候QC的作用會比較明顯姓建。如果數(shù)據(jù)庫一共往QC中寫入了約800W次緩存诞仓,但是實際命中的只有約500W次。也就是說速兔,每一個緩存的使用率約為0.66次墅拭。很難說,該緩存的作用是否大于QC系統(tǒng)所帶來的開銷涣狗。但是有一點是很肯定的谍婉,QC緩存的作用是很微小的,如果應(yīng)用層能夠?qū)崿F(xiàn)緩存镀钓,將可以忽略QC的效果穗熬。
————-下面是關(guān)于Query Cache相關(guān)參數(shù)—————–
mysql> show variables like '%query_cache%';
+------------------------------+---------+
| Variable_name????????????????| Value?? |
+------------------------------+---------+
| have_query_cache???????????? | YES???? |
| query_cache_limit????????????| 1048576 |
| query_cache_min_res_unit???? | 4096????|
| query_cache_size???????????? | 1048576 |
| query_cache_type???????????? | OFF???? |
| query_cache_wlock_invalidate | OFF???? |
+------------------------------+---------+
6 rows in set (0.00 sec)
query_cache_size:設(shè)置Query Cache所使用的內(nèi)存大小,默認(rèn)值為0丁溅,大小必須是1024的整數(shù)倍唤蔗,如果不是整數(shù)倍,MySQL會自動調(diào)整降低最小量以達到1024的倍數(shù)。
query_cache_type:控制Query Cache功能的開關(guān)妓柜,可以設(shè)置為0(OFF)箱季,1(ON)和2(DEMAND)三種:0表示關(guān)閉Query Cache功能,任何情況下都不會使用Query Cache领虹;1表示開啟Query Cache功能规哪,但是當(dāng)SELECT語句中使用的SQL_NO_CACHE提示后,將不使用Query Cache塌衰;2(DEMAND)表示開啟Query Cache功能诉稍,但是只有當(dāng)SELECT語句中使用了SQL_CACHE提示后,才使用Query Cache最疆。
query_cache_limit:允許Cache的單條Query結(jié)果集的最大容量杯巨,默認(rèn)是1MB,超過此參數(shù)設(shè)置的Query結(jié)果集將不會被Cache努酸。
query_cache_min_res_unit:設(shè)置Query Cache中每次分配內(nèi)存的最小空間大小服爷,也就是每個Query的Cache最小占用的內(nèi)存空間大小。
query_alloc_block_size:緩存的塊大小获诈,默認(rèn)為8192字節(jié)仍源。
query_cache_wlock_invalidate:控制當(dāng)有寫鎖加在表上的時候,是否先讓該表相關(guān)的Query Cache失效舔涎,1(TRUE)笼踩,在寫鎖定的同時將使該表相關(guān)的所有Query Cache 失效。0(FALSE)亡嫌,在鎖定時刻仍然允許讀取該表相關(guān)的Query Cache嚎于。
Qcache_lowmem_prunes:這是一個狀態(tài)變量(show status),當(dāng)緩存空間不夠需要釋放舊的緩存時挟冠,該值會自增于购。
如何確認(rèn)一個系統(tǒng)的 Query Cache 的運行是否健康,命中率如何知染,設(shè)置量是否足夠肋僧?
mysql> show global status like '%Qcache%';
+-------------------------+---------+
| Variable_name?????????? | Value?? |
+-------------------------+---------+
| Qcache_free_blocks??????| 1?????? |
| Qcache_free_memory??????| 1031832 |
| Qcache_hits???????????? | 0?????? |
| Qcache_inserts??????????| 0?????? |
| Qcache_lowmem_prunes????| 0?????? |
| Qcache_not_cached?????? | 128998??|
| Qcache_queries_in_cache | 0?????? |
| Qcache_total_blocks???? | 1?????? |
+-------------------------+---------+
8 rows in set (0.00 sec)
mysql> show global status like '%Com_select%';
+---------------+--------+
| Variable_name | Value |
+---------------+--------+
| Com_select????| 129157 |
+---------------+--------+
Qcache_free_blocks:目前還處于空閑狀態(tài)的Query Cache中內(nèi)存Block數(shù)目。
Qcache_free_memory:目前還處于空閑狀態(tài)的Query Cache內(nèi)存總量控淡。
Qcache_hits:Query Cache命中次數(shù)色瘩。
Qcache_inserts:向Query Cache中插入新的Query Cache的次數(shù),也就是沒有命中的次數(shù)逸寓。
Qcache_lowmem_prunes:當(dāng)Query Cache內(nèi)存容量不夠居兆,需要從中刪除老的Query Cache以給新的Cache對象使用的次數(shù)。
Qcache_not_cached:沒有被Cache的SQL數(shù)竹伸,包括無法被Cache的SQL以及由于query_cache_type設(shè)置的不會被Cache 的?SQL泥栖。
Qcache_queries_in_cache:目前在Query Cache中的SQL數(shù)量簇宽。
Qcache_total_blocks:Query Cache中總的Block數(shù)量。
可以根據(jù)這幾個狀態(tài)計算出Cache命中率吧享,計算出Query Cache大小設(shè)置是否足夠魏割。
寫在前面:MySQL的Query Cache大部分情況下其實只是雞肋而已,建議全面禁用钢颂,默認(rèn)關(guān)閉钞它。當(dāng)然了,或許在你的場景下還是挺好的殊鞭,還能發(fā)揮作用遭垛,那就繼續(xù)使用吧,把本文當(dāng)做參考就好操灿。不過锯仪,可能有的人人為只需要把query_cache_size大小調(diào)整為0就可以了,可以忽略query_cache_type參數(shù)的值趾盐,反正它也是可以在線調(diào)整的庶喜。事實果真如此嗎?讓我們來實際模擬測試下就知道了救鲤。
我們模擬了以下幾種場景:
1久窟、初始化時,同時設(shè)置query_cache_size和query_cache_type的值為0本缠;
2斥扛、初始化時,設(shè)置query_cache_size = 0搓茬,但設(shè)置query_cache_type = 1;
3队他、初始化時卷仑,設(shè)置query_cache_size = 0,query_cache_type = 1麸折,但是啟動后立刻修改query_cache_type = 0 ;
4锡凝、初始化時,設(shè)置query_cache_size = 0垢啼,query_cache_type = 0窜锯,但是啟動后立刻修改query_cache_type = 1 ;
5、初始化時芭析,設(shè)置query_cache_size = xMB锚扎,query_cache_type = 1,但是啟動后立刻修改query_cache_type = 0 ;
經(jīng)過測試馁启,可以得到下面幾個重要結(jié)論(詳細測試過程請見最后):
1驾孔、想要徹底關(guān)閉query cache芍秆,務(wù)必在一開始就設(shè)置query_cache_type = 0,即便是啟動后將query_cache_type從1改成0翠勉,也不行妖啥;
2、即便query_cache_size = 0对碌,但query_cache_type非0的話荆虱,在實際環(huán)境中,可能會頻繁發(fā)生Waiting for query cache lock朽们;
3怀读、一開始就設(shè)置query_cache_type = 0的話,沒有辦法在運行過程中再次動態(tài)啟用华坦,反過來則可以愿吹。也就是說,一開始是啟用query cache的惜姐, 在運行過程中將其關(guān)閉犁跪,但事實上仍然會發(fā)生Waiting for query cache lock,并沒有真正的關(guān)閉歹袁;
詳細測試過程:
一坷衍、測試方法
采用sysbench模擬并發(fā)OLTP請求:
$ sysbench --test=tests/db/oltp.lua --oltp_tables_count=10 --oltp-table-size=100000 --rand-init=on --num-threads=64 --oltp-read-only=off --report-interval=10 --rand-type=uniform --max-time=1800 --max-requests=0 run
二、具體幾種測試模式
1条舔、一直關(guān)閉QC(query cache的簡寫枫耳,下同),即 query_cache_size = 0孟抗, query_cache_type = 0
測試過程中迁杨,一直都沒有和query cache lock相關(guān)的狀態(tài)出現(xiàn),結(jié)果tps:2295.34凄硼。
2铅协、啟用QC,但QC size 設(shè)置為 0摊沉,即:query_cache_size = 0狐史,query_cache_type = 1
測試過程中,一直有 Waiting for query cache lock 狀態(tài)出現(xiàn)说墨,結(jié)果tps:2272.52骏全。
3、啟用QC尼斧,但QC size為0姜贡,但啟動時立刻關(guān)閉QC,即初始化時 query_cache_size = 0棺棵,query_cache_type = 1鲁豪,啟動后立刻修改query_cache_type = 0
測試過程中潘悼,也一直有 Waiting for query cache lock 狀態(tài)出現(xiàn),結(jié)果tps:2311.54爬橡。
4治唤、關(guān)閉QC,但啟動后立刻啟用QC糙申,即初始化時 query_cache_size = 0宾添,query_cache_type = 0,啟動后立刻修改query_cache_type = 1
這時柜裸,會提示報錯信息:失斅粕隆:ERROR 1651 (HY000): Query cache is disabled; restart the server with query_cache_type=1 to enable it。也就是說疙挺,如果一開始就關(guān)閉 QC 的話扛邑,是沒辦法在運行過程中動態(tài)再啟用QC的。
5铐然、啟用QC蔬崩,并設(shè)置QC size為256M,即query_cache_size = 256M搀暑,query_cache_type = 1
這種情況下沥阳,在測試過程中一直有Waiting for query cache lock狀態(tài)出現(xiàn),并且結(jié)果tps也很差自点,只有1395.39(幾個案例中最差的一種)桐罕。
6、啟用QC桂敛,設(shè)置QC size為256M功炮,但啟動后立刻關(guān)閉QC,即query_cache_size = 256M术唬,query_cache_type = 1薪伏,啟動后立刻修改query_cache_type = 0
這種情況下,在測試過程中也一直有Waiting for query cache lock狀態(tài)出現(xiàn)碴开,結(jié)果tps:2295.79(在這個模式下毅该,如果設(shè)置query_cache_type = 2博秫,效果也不佳)潦牛。
第三種模式下,雖然看起來tps還不錯挡育,但畢竟上面只是簡單模擬測試巴碗,實際情況下如果有頻繁的query cache lock的話,tps肯定不會太好看即寒。因此橡淆,總的來說召噩,想要獲得較高tps的話,最好還是一開始就關(guān)閉QC逸爵,不要心存僥幸或者固守陳規(guī)具滴。
轉(zhuǎn)自:http://www.ywnds.com/?p=7386