摘要:應(yīng)用程序無須關(guān)心是通過查詢緩存返回的結(jié)果還是實際執(zhí)行返回的結(jié)果。表示只有在查詢語句中明確寫明的語句才放入查詢緩存。在查詢緩存中分配內(nèi)存塊時的最小單位。能夠緩存的最大査詢結(jié)果。
個人博客地址:http://www.xixinice.com
MySQL執(zhí)行一個查詢過程:
當(dāng)我們向MySQL發(fā)送一個請求的時候,MySQL到底做了什么:
1.客戶端發(fā)送一條查詢給服務(wù)器
2.服務(wù)器先檢查查詢緩存,如果命中了緩存,則立刻返回存儲在緩存中的結(jié)果。否則進入下一階段。
3.服務(wù)器端進行SQL解析、預(yù)處理,再由優(yōu)化器生成對應(yīng)的執(zhí)行計劃。
4.MySQL根據(jù)優(yōu)化器生成的執(zhí)行計劃,調(diào)用存儲引擎的API來執(zhí)行查詢
5.將結(jié)果返回給客戶端。
mysql 主要是由 server 層和存儲層兩部分構(gòu)成的。
server 層主要包括連接器、查詢緩存,分析器、優(yōu)化器、執(zhí)行器。
存儲層主要是用來存儲和查詢數(shù)據(jù)的,常用的存儲引擎有 InnoDB、MyISAM,
(1) MySQL客戶端/服務(wù)器通信協(xié)議
MySQL客戶端和服務(wù)器之的通信協(xié)議是“半雙工”的,這就意味著,在任何一個時刻,要么是由服務(wù)器向客戶端發(fā)送數(shù)據(jù),要么是由客戶端向服務(wù)器發(fā)送數(shù)據(jù),這兩個動作不能同時發(fā)生。所以我們無法也無須將一個消息切成小塊獨立來發(fā)送。
優(yōu)缺點:
這種協(xié)議讓MySQL通信簡單快速,但是也從很多地方限制了 MySQL。
一個明顯的限制是,這意味著沒法進行流量控制。一旦一端開始發(fā)送消息,另一端要接收完整個消息才能響應(yīng)它。這就像采回拋球的游戲:在任何時刻,只有一個人能控制球,而且只有控制球的人才能將球拋回去(發(fā)送消息)。
(2).連接器
MySQL客戶端和服務(wù)端建立連接,獲取當(dāng)前連接用戶的權(quán)限
(3)查詢緩存
在解析一個查詢語句之前,如果查詢緩存是打開的,MySQL會檢查這個緩存,是否命中查詢緩存中的數(shù)據(jù)。這個檢查是通過一個大小寫敏感的哈希查找實現(xiàn)的。
查詢和緩存中的查詢即使只有一個字節(jié)不同,那也不會匹配緩存結(jié)果,這種情況下查詢
就會進入下一階段的處理。
如果當(dāng)前的查詢恰好命中了查詢緩存,那么在返回查詢結(jié)果之前 MySQL會檢查一次用
戶權(quán)限。這仍然是無須解析查詢SQL語句的,因為在查詢緩存中已經(jīng)存放了當(dāng)前查詢需
要訪問的表信息。如果權(quán)限沒有問題, MySQL會跳過所有其他階段,直接從緩存中拿
到結(jié)果并返回給客戶端。這種情況下,查詢不會被解析,不用生成執(zhí)行計劃,不會被執(zhí)行.
ps:注意在 mysql8 后已經(jīng)沒有查詢緩存這個功能了,因為這個緩存非常容易被清空掉,命中率比較低。
(3).分析器
既然沒有查到緩存,就需要開始執(zhí)行 sql 語句了,在執(zhí)行之前肯定需要先對 sql 語句進行解析。 分析器主要對 sql 語句進行語法和語義分析,檢查單詞是否拼寫錯誤,還有檢查要查詢的表或字段是否存在
(4)查詢優(yōu)化
查詢的生命周期的下一步是將一個SQL轉(zhuǎn)換成一個執(zhí)行計劃, MySQL再依照這個執(zhí)行
計劃和存儲引擎進行交互。這包括多個子階段:解析SQL、預(yù)處理、優(yōu)化SQ執(zhí)行計劃。
這個過程中任何錯誤(例如語法錯誤)都可能終止查詢。
2.關(guān)于查詢緩存
(1)
MySQL 判斷緩存命中的方法很簡單:緩存存放在一個引用表中,通過一個哈希值引用。
MySOL查詢緩存保存查詢返回的完整結(jié)果。當(dāng)查詢命中該緩存, MySQL會立刻返回結(jié)果跳過了 解析,優(yōu)化和執(zhí)行階段
查詢緩存系統(tǒng)會跟蹤查迫中涉及的每個表,如果這些表發(fā)生變化,那么和這個表相關(guān)的的存數(shù)據(jù)都將失效。
這種機制效率看起來比較低,因為數(shù)據(jù)表變化時很有可能對查詢結(jié)果并沒有變更,但是這種簡單實現(xiàn)代價很小,而這點對于一個非常繁忙的系統(tǒng)來說非常重要。
查詢緩存系統(tǒng)對應(yīng)用程序是完全透明的。應(yīng)用程序無須關(guān)心 MySQL是通過查詢緩存返回的結(jié)果還是實際執(zhí)行返回的結(jié)果。事實上,這兩種方式執(zhí)行的結(jié)果是完全相同的。換句話說,查詢緩存無須使用任何語法。無論是 MYSQL開啟成關(guān)閉查詢緩在,對應(yīng)用程序都是透明的。
(2)判斷緩存命中
當(dāng)判斷緩存是否命中時, MySQL不會解析、“正規(guī)化”或者參數(shù)化查詢語句,而是直接使用SQL語句和客戶端發(fā)送過來的其他原始信息,在字符上不同,例如空格、注釋,在何的不同,都會導(dǎo)致緩存的不中。
當(dāng)查詢語句中有一些不確定的數(shù)據(jù)時,則不會被緩存,例如包含函數(shù)NOW()或者 CURRENT_DATE()
的查詢不會被緩存.
誤區(qū):
我們常聽到:“如果查詢中包含一個不確定的函數(shù), MySQL則不會檢查查詢緩存”。這個說法是不正確的。
因為在檢查查詢緩存的時候,還沒有解析SQL語句,所以MySQL并不知道查詢語句中是否包含這類函數(shù)。
在檢查查詢緩存之前, MySQL只做一件事情,就是通過一個大小寫不敏感的檢查看看SQL語句是不是以5EL開頭。
準(zhǔn)確的說法應(yīng)該是:“如果查詢語句中包含任何的不確定函數(shù),那么在查詢緩存中是不可能找到緩存結(jié)果的”。
注意點:
MySQL的查詢緩存在很多時候可以提升查詢性能,在使用的時候,有一些問題需要特別注意。首先,打開查詢緩存對讀和寫操作都會帶來額外的消耗:
1.讀查詢在開始之前必須先檢查是否命中緩存
2.如果這個讀查詢可以被緩存,那么當(dāng)完成執(zhí)行后, MySQL若發(fā)現(xiàn)查詢緩存中沒有這個查詢,會將其結(jié)果存入查詢緩存,這會帶來額外的系統(tǒng)消耗。
3.這對寫操作也會有影響,因為當(dāng)向某個表寫入數(shù)據(jù)的時候, MySQL必須將對應(yīng)表的所有緩存都設(shè)置失效。如果查詢緩存非常大或者碎片很多,這個操作就可能會帶來大系統(tǒng)消耗(設(shè)置了很多的內(nèi)存給查詢緩存用的時候)
如果查詢緩存使用了很大量的內(nèi)存,緩存失效操作就可能成為一個非常嚴(yán)重的問題瓶頸
如果緩存中存放了大量的查詢結(jié)果,那么緩存失效操作時整個系統(tǒng)都可能會僵死一會
因為這個操作是靠一個全局鎖操作保護的,所有需要做該操作的查詢都要等待這個鎖,
而且無論是檢測是否命中緩存、還是緩存失效檢測都需要等待這個全局鎖。
(3)什么情況下查詢緩存能發(fā)揮作用
理論上,可以通過觀察打開或者關(guān)閉查詢緩存時候的系統(tǒng)效率來決定是否需要開啟查詢。
對手那些需要消耗大量資源的查詢通常都是非常適合緩存的。
例如一些匯總計算查詢具體的如 COUNT()等。總地來說,對于復(fù)雜的 SELECT語句都可以使用查詢緩存,
例如多表JOIN后還需要做排序和分頁,這類查詢每次執(zhí)行消耗都很大,但是返回的結(jié)果集卻很小,非常適合查詢緩存。
不過需要注意的是,涉及的表上 UPDATE、 DELETE和 INSERT操作相比 SELECT來說要非常少才行。
判斷查詢緩存是否有效的直接數(shù)據(jù)是命中率。就是使用查詢緩存返回結(jié)果占總查詢的比率
不過緩存中率是一個很難判斷的數(shù)值。命中率多大才是好的命中率。具體情況,具體分析。
只要查詢緩存帶來的效率提升大于查詢緩存帶來的額外消耗,即使30%命中率對系統(tǒng)性能提升也有很大好處。另外,緩存了哪些查詢也很重要,例如,被緩存的查詢本身消耗非常巨大,那么即使緩存命中率非常低,也仍然會對系統(tǒng)性能提升有好處
緩存未命中可能有如下幾種原因:
1.查詢語句無法被緩存,可能是因為查詢中包含一個不確定的函數(shù)(如 CURREN_DATE)或者查詢結(jié)果太大而無法緩存。這都會導(dǎo)致狀態(tài)值 Cache not cached增加。
2.MySQL從未處理這個查詢,所以結(jié)果也從不曾被緩存過。
3.還有一種情況是雖然之前緩存了查詢結(jié)果,但是由于查詢緩存的內(nèi)存用完了,MySQL需要將某些緩存“逐出”,或者由于數(shù)據(jù)表被修改導(dǎo)致緩存失效。
如果你的服務(wù)器上有大量緩存未命中,但是實際上絕大數(shù)查詢都被緩存了,那么一定是有如下情況發(fā)生:
1.查詢緩存還沒有完成預(yù)熱。也就是說, MySQL還沒有機會將查詢結(jié)果都緩存起來。
2.查詢語句之前從未執(zhí)行過。如果你的應(yīng)用程序不會重復(fù)執(zhí)行一條查詢語句,那么即使完成預(yù)熱仍然會有很多緩存未命中
3.緩存失效操作太多了。
(4)如何配置 和維護查詢緩存
query_cache_type
是否打開查詢緩存??梢栽O(shè)置成0FN或 DEMAND。 DEMAND表示只有在查詢語句中明確寫明SQL_ CACHE的語句才放入查詢緩存。這個變量可以是會話級別的也可以是全局級別的
query_cache_size
查詢緩存使用的總內(nèi)存空間,單位是字節(jié)。這個值必須是1024的整數(shù)倍,否則 MySQL實際分配的數(shù)據(jù)會和你指定的略有不同。
query_cahce_min_res_unit
在查詢緩存中分配內(nèi)存塊時的最小單位。
query_chache_limit
MySQL能夠緩存的最大査詢結(jié)果。如果查詢結(jié)果大于這個值,則不會被緩存。因為査詢緩存在數(shù)據(jù)生成的時候就開始嘗試緩存數(shù)據(jù),所以只有當(dāng)結(jié)果全部返回后,才知道查詢結(jié)果是否超出限制
如果超出, MySQL則增加狀態(tài)值 Cache_not_cached,并將結(jié)果從查詢緩存中刪除如果你事先知道有很多這樣的情況發(fā)生,那么建議在查詢語句中加入
(5)替代方案
MySQL查詢緩存工作的原則是:執(zhí)行查詢最快的方式就是不去執(zhí)行,但是查詢?nèi)匀恍枰l(fā)送到服務(wù)器端,服務(wù)器也還需要做一點點工作。如果對于某些查詢完全不需要與服務(wù)器通信效果會如何呢?這時客戶端的緩存可以很大程度上幫你分擔(dān) MySQL服務(wù)器的壓力
總結(jié):
完全相同的查詢在重復(fù)執(zhí)行的時候,查詢緩存可以立即返回結(jié)果,而無須在數(shù)據(jù)庫中重新執(zhí)行一次。根據(jù)我們的經(jīng)驗,在高并發(fā)壓力環(huán)境中在詢緩存會導(dǎo)致系統(tǒng)性能的下降,甚至僵死。
如果一定要使用查詢緩存,那么不要設(shè)置太大內(nèi)存,而且只有在確收益的時候才使用。
那該如何判斷是否應(yīng)該使用查詢緩存呢?建議使Percona server.,觀察更細致的日志,并做一些簡單的計算。還可以查看緩存命中率(并不總是有用)、“ NSERTS和 SELECT比率”(這個參數(shù)也并不直觀)、或者“命中和寫入比率”(這個參考意義較大)。
查詢緩存是一個非常方便的緩存,對應(yīng)用程序完全透明,無須任何額外的編碼,但是、如果希望有更高的緩存效率,我們建議使cache 或者其他類似的解決方案。
ps:文章參考《高性能MySQL》一書
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/62095.html
閱讀 3508·2023-04-26 02:00
閱讀 3100·2021-11-22 13:54
閱讀 1711·2021-08-03 14:03
閱讀 723·2019-08-30 15:52
閱讀 3102·2019-08-29 12:30
閱讀 2431·2019-08-26 13:35
閱讀 3377·2019-08-26 13:25
閱讀 3013·2019-08-26 11:39