MySQL 執行過程與查詢緩存

MySQL執行一個查詢過程:
當我們向MySQL發送一個請求的時候,MySQL到底做了什麼:

1.客戶端發送一條查詢給服務器
2.服務器先檢查查詢緩存,如果命中了緩存,則立刻返回存儲在緩存中的結果。否則進入下一階段。
3.服務器端進行SQL解析、預處理,再由優化器生成對應的執行計劃。
4.MySQL根據優化器生成的執行計劃,調用存儲引擎的API來執行查詢
5.將結果返回給客戶端。

mysql 主要是由 server 層和存儲層兩部分構成的。
server 層主要包括連接器、查詢緩存,分析器、優化器、執行器。
存儲層主要是用來存儲和查詢數據的,常用的存儲引擎有 InnoDB、MyISAM,

(1) MySQL客戶端/服務器通信協議

MySQL客戶端和服務器之的通信協議是“半雙工”的,這就意味着,在任何一個時刻,要麼是由服務器向客戶端發送數據,要麼是由客戶端向服務器發送數據,這兩個動作不能同時發生。所以我們無法也無須將一個消息切成小塊獨立來發送。

優缺點:
這種協議讓MySQL通信簡單快速,但是也從很多地方限制了 MySQL。
一個明顯的限制是,這意味着沒法進行流量控制。一旦一端開始發送消息,另一端要接收完整個消息才能響應它。這就像採回拋球的遊戲:在任何時刻,只有一個人能控制球,而且只有控制球的人才能將球拋回去(發送消息)。

(2).連接器

 MySQL客戶端和服務端建立連接,獲取當前連接用戶的權限

(3)查詢緩存
在解析一個查詢語句之前,如果查詢緩存是打開的,MySQL會檢查這個緩存,是否命中查詢緩存中的數據。這個檢查是通過一個大小寫敏感的哈希查找實現的。
查詢和緩存中的查詢即使只有一個字節不同,那也不會匹配緩存結果,這種情況下查詢
就會進入下一階段的處理。

如果當前的查詢恰好命中了查詢緩存,那麼在返回查詢結果之前 MySQL會檢查一次用
戶權限。這仍然是無須解析查詢SQL語句的,因爲在查詢緩存中已經存放了當前查詢需
要訪問的表信息。如果權限沒有問題, MySQL會跳過所有其他階段,直接從緩存中拿
到結果並返回給客戶端。這種情況下,查詢不會被解析,不用生成執行計劃,不會被執行.

ps:注意在 mysql8 後已經沒有查詢緩存這個功能了,因爲這個緩存非常容易被清空掉,命中率比較低。

(3).分析器

既然沒有查到緩存,就需要開始執行 sql 語句了,在執行之前肯定需要先對 sql 語句進行解析。
分析器主要對 sql 語句進行語法和語義分析,檢查單詞是否拼寫錯誤,還有檢查要查詢的表或字段是否存在

(4)查詢優化

查詢的生命週期的下一步是將一個SQL轉換成一個執行計劃, MySQL再依照這個執行
計劃和存儲引擎進行交互。這包括多個子階段:解析SQL、預處理、優化SQ執行計劃。
這個過程中任何錯誤(例如語法錯誤)都可能終止查詢。

2.關於查詢緩存

(1)
MySQL 判斷緩存命中的方法很簡單:緩存存放在一個引用表中,通過一個哈希值引用。
MySOL查詢緩存保存查詢返回的完整結果。當查詢命中該緩存, MySQL會立刻返回結果跳過了 解析,優化和執行階段

查詢緩存系統會跟蹤查迫中涉及的每個表,如果這些表發生變化,那麼和這個表相關的的存數據都將失效。

這種機制效率看起來比較低,因爲數據表變化時很有可能對查詢結果並沒有變更,但是這種簡單實現代價很小,而這點對於一個非常繁忙的系統來說非常重要。

查詢緩存系統對應用程序是完全透明的。應用程序無須關心 MySQL是通過查詢緩存返回的結果還是實際執行返回的結果。事實上,這兩種方式執行的結果是完全相同的。換句話說,查詢緩存無須使用任何語法。無論是 MYSQL開啓成關閉查詢緩在,對應用程序都是透明的。

(2)判斷緩存命中

當判斷緩存是否命中時, MySQL不會解析、“正規化”或者參數化查詢語句,而是直接使用SQL語句和客戶端發送過來的其他原始信息,在字符上不同,例如空格、註釋,在何的不同,都會導致緩存的不中。

當查詢語句中有一些不確定的數據時,則不會被緩存,例如包含函數NOW()或者 CURRENT_DATE()
的查詢不會被緩存.

誤區:
我們常聽到:“如果查詢中包含一個不確定的函數, MySQL則不會檢查查詢緩存”。這個說法是不正確的。

因爲在檢查查詢緩存的時候,還沒有解析SQL語句,所以MySQL並不知道查詢語句中是否包含這類函數。

在檢查查詢緩存之前, MySQL只做一件事情,就是通過一個大小寫不敏感的檢查看看SQL語句是不是以5EL開頭。

準確的說法應該是:“如果查詢語句中包含任何的不確定函數,那麼在查詢緩存中是不可能找到緩存結果的”。

注意點:
MySQL的查詢緩存在很多時候可以提升查詢性能,在使用的時候,有一些問題需要特別注意。首先,打開查詢緩存對讀和寫操作都會帶來額外的消耗:

1.讀查詢在開始之前必須先檢查是否命中緩存
2.如果這個讀查詢可以被緩存,那麼當完成執行後, MySQL若發現查詢緩存中沒有這個查詢,會將其結果存入查詢緩存,這會帶來額外的系統消耗。
3.這對寫操作也會有影響,因爲當向某個表寫入數據的時候, MySQL必須將對應表的所有緩存都設置失效。如果查詢緩存非常大或者碎片很多,這個操作就可能會帶來大系統消耗(設置了很多的內存給查詢緩存用的時候)

如果查詢緩存使用了很大量的內存,緩存失效操作就可能成爲一個非常嚴重的問題瓶頸
如果緩存中存放了大量的查詢結果,那麼緩存失效操作時整個系統都可能會僵死一會

因爲這個操作是靠一個全局鎖操作保護的,所有需要做該操作的查詢都要等待這個鎖,
而且無論是檢測是否命中緩存、還是緩存失效檢測都需要等待這個全局鎖。

(3)什麼情況下查詢緩存能發揮作用
理論上,可以通過觀察打開或者關閉查詢緩存時候的系統效率來決定是否需要開啓查詢。

對手那些需要消耗大量資源的查詢通常都是非常適合緩存的。
例如一些彙總計算查詢具體的如 COUNT()等。總地來說,對於複雜的 SELECT語句都可以使用查詢緩存,
例如多表JOIN後還需要做排序和分頁,這類查詢每次執行消耗都很大,但是返回的結果集卻很小,非常適合查詢緩存。

不過需要注意的是,涉及的表上 UPDATE、 DELETE和 INSERT操作相比 SELECT來說要非常少才行。

判斷查詢緩存是否有效的直接數據是命中率。就是使用查詢緩存返回結果佔總查詢的比率

不過緩存中率是一個很難判斷的數值。命中率多大才是好的命中率。具體情況,具體分析。

只要查詢緩存帶來的效率提升大於查詢緩存帶來的額外消耗,即使30%命中率對系統性能提升也有很大好處。另外,緩存了哪些查詢也很重要,例如,被緩存的查詢本身消耗非常巨大,那麼即使緩存命中率非常低,也仍然會對系統性能提升有好處

緩存未命中可能有如下幾種原因:

1.查詢語句無法被緩存,可能是因爲查詢中包含一個不確定的函數(如 CURREN_DATE)或者查詢結果太大而無法緩存。這都會導致狀態值 Cache not cached增加。
2.MySQL從未處理這個查詢,所以結果也從不曾被緩存過。

3.還有一種情況是雖然之前緩存了查詢結果,但是由於查詢緩存的內存用完了,MySQL需要將某些緩存“逐出”,或者由於數據表被修改導致緩存失效。

如果你的服務器上有大量緩存未命中,但是實際上絕大數查詢都被緩存了,那麼一定是有如下情況發生:

1.查詢緩存還沒有完成預熱。也就是說, MySQL還沒有機會將查詢結果都緩存起來。
2.查詢語句之前從未執行過。如果你的應用程序不會重複執行一條查詢語句,那麼即使完成預熱仍然會有很多緩存未命中
3.緩存失效操作太多了。

(4)如何配置 和維護查詢緩存

query_cache_type

是否打開查詢緩存。可以設置成0FN或 DEMAND。 DEMAND表示只有在查詢語句中明確寫明SQL_ CACHE的語句才放入查詢緩存。這個變量可以是會話級別的也可以是全局級別的

query_cache_size

查詢緩存使用的總內存空間,單位是字節。這個值必須是1024的整數倍,否則 MySQL實際分配的數據會和你指定的略有不同。

query_cahce_min_res_unit

在查詢緩存中分配內存塊時的最小單位。

query_chache_limit

MySQL能夠緩存的最大査詢結果。如果查詢結果大於這個值,則不會被緩存。因爲査詢緩存在數據生成的時候就開始嘗試緩存數據,所以只有當結果全部返回後,才知道查詢結果是否超出限制

如果超出, MySQL則增加狀態值 Cache_not_cached,並將結果從查詢緩存中刪除如果你事先知道有很多這樣的情況發生,那麼建議在查詢語句中加入

(5)替代方案

MySQL查詢緩存工作的原則是:執行查詢最快的方式就是不去執行,但是查詢仍然需要發送到服務器端,服務器也還需要做一點點工作。如果對於某些查詢完全不需要與服務器通信效果會如何呢?這時客戶端的緩存可以很大程度上幫你分擔 MySQL服務器的壓力

總結:

完全相同的查詢在重複執行的時候,查詢緩存可以立即返回結果,而無須在數據庫中重新執行一次。根據我們的經驗,在高併發壓力環境中在詢緩存會導致系統性能的下降,甚至僵死。

如果一定要使用查詢緩存,那麼不要設置太大內存,而且只有在確收益的時候才使用。

那該如何判斷是否應該使用查詢緩存呢?建議使Percona server.,觀察更細緻的日誌,並做一些簡單的計算。還可以查看緩存命中率(並不總是有用)、“ NSERTS和 SELECT比率”(這個參數也並不直觀)、或者“命中和寫入比率”(這個參考意義較大)。

查詢緩存是一個非常方便的緩存,對應用程序完全透明,無須任何額外的編碼,但是、如果希望有更高的緩存效率,我們建議使cache 或者其他類似的解決方案。

ps:文章參考《高性能MySQL》一書

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章