看了《MySQL高性能》以及幾位博客大佬的博客。概要總結一下自己的理解。
先給出MySQL基本框架示意圖,這張圖的風格很喜歡,目前還不知道用什麼畫出來的,先用一下
咋一看圖好像有點複雜,好像亂七八糟的。
不慌不慌,我們慢慢來,保證這篇看完就立馬能大致全部瞭解了。
一般可以把MySQL分爲Server層和存儲引擎層兩部分。
這一篇主要把Server層給弄清楚就可。
-
Server層:包含了連接器、查詢緩存、分析器、優化器、執行器等,這裏涵蓋了MySQL的大多數核心功能區以及所有的內置函數。
- 內置函數:日期,時間,數學和加密函數等;
- 所有的跨存儲引擎的功能都在這一層實現:存儲過程、觸發器、視圖等。
-
存儲引擎層:負責着數據的存儲和提取,並提供了讀寫接口。不同的引擎有着各自的方式。
- create table時如果不指定引擎類型,默認使用的就是InnoDB。
接下來就是server層了。
一、連接器
功能就是負責跟客戶端建立連接,獲取權限,維持和管理連接。我們可以通過這個連接器呢,把客戶端和server層連接起來,從而登錄到mysql。
- 連接過程
- 經典的TCP握手之後,服務器會開始驗證身份。這個時候要用到我們輸入的用戶名和密碼
- 用戶名密碼正確,連接器就會回到權限表裏找到我們所擁有的權限。之後在這個連接面裏的權限判斷邏輯,都會依賴於此時讀到的權限。
- 連接完成之後
- 如果不進行後續操作,這個連接就會空閒下來。可以使用show processlist命令來查看它。
- 若很長時間都沒有動靜,那麼連接器就會自動斷開,這個時間默認的是8小時,是由wait_timeout控制的。
報告:我想修改wait_timeout時間,八小時太短了,滿足不了我。
雖然很詫異,但是這是沒有問題的啦
wait_timeout這個當然是可以手動更改的,更改方法如下
show global variables like 'wait_timeout'; -- 可查看當前wait_timeout時間爲多少;
set global wait_timeout=36000; -- 修改wait_timeout爲36000;
-- 當然咱們有圖有真相。
關於上述的連接過程中連接器需要讀的部分權限表
目前知道的這四個權限表
-
user權限表:記錄允許連接到服務器的用戶帳號信息,裏面的權限是全局級的。
-
db權限表:記錄各個帳號在各個數據庫上的操作權限。
-
table_priv權限表:記錄數據表級的操作權限。
-
columns_priv權限表:記錄數據列級的操作權限。
關於長連接和短鏈接
-
長連接:指的就是長時間使用同一連接的情況,也就是連接成功後,長時間保持客戶端與服務端的連接狀態。
可表示爲:
連接 -> 數據傳輸 -> 保持連接 -> 數據傳輸 -> 保持連接 … -> 關閉連接;
因此這就需要長連接在沒有數據通信時,定時發送數據包,以維持連接狀態。
-
短鏈接:在沒有數據傳輸時直接關閉就行了。
可表示爲:
連接 -> 數據傳輸 -> 關閉連接;
由於建立連接過程很複雜,所以我們儘量要減少建立連接的動作,也就是儘量使用長連接。
但是呢但是 長連接也存在着一個問題
-
如果全部使用長連接的話,會發現MySQL佔用內存特別快。
爲什麼呢?
- 因爲MySQL在執行的時候臨時使用的內存時管理在連接對象裏面的,這些資源只有在連接斷開的時候會釋放。所以若長連接鏈積累下來,就可能會導致內存佔用太大。然後呢,就會被系統給強制殺死。
表現出來就是MySQL會異常重啓
當然也有着解決方案
- 定期斷開長連接。
不過如果使用的時MySQL5.7或者更高的版本的話。可以通過執行mysql_reset_connection來重新初始化鏈接資源。好的地方在這個過程不需要重連和重新做權限驗證,而且還會將連接恢復到剛剛創建完時的狀態。妙哉妙哉
查詢緩存
簡介一下:就是之前查詢過的語句被記錄下來了,當你再次使用那個語句時,就不需要進行下面的分析優化執行了,直接在緩存中找即可。
緩存是怎麼被存的呢?
- 之前執行過的語句以及結果會以key-value對的形式,被直接存放在內存中。key是查詢的語句,value是查詢的結果。
看上去效率可高了呢。。
但其實大多數情況下我們都會不被建議使用查詢緩存。
???爲什麼,明明這麼好用的東西啊
別急別急看這裏 (經過尋找各種大佬博客本蒻j終於找到了答案)
- 因爲查詢緩存的失效非常的頻繁,只要有對一個表的更新,這個表上的所有查詢緩存都會被清空。這就造成了這麼一種現象:明明你費勁把結果存了起來,結果還沒使用呢,就被一個更新全部清空了。對於頻繁需要更新的數據庫來說,查詢緩存的命中率會非常的低。當然在某些靜態表上,就是很久纔會更新一次的表上,比如一個系統配置表,就比較適合使用查詢緩存。
當不想使用查詢緩存的時候,可以將參數query_cache_type設置成DEMAND。
這之後對於默認的SQL語句都不適用查詢緩存了。當有些你確定要使用查詢緩存的語句,可以用SQL_CACHE顯示指定。比如
select sql_cache * from employee where salary = 3000;
ps:MySQL 8.0版本之後直接就將查詢緩存的整塊功能刪掉了 ,也就是說從8.0開始就徹底沒有這個功能了。
分析器
簡介:如果沒有命中緩存的話,就會開始真正的執行SQL語句了。分析器中簡單的說包含了詞法分析和語法分析。
給個例子分析一下
select * from employee where salary = 3000;
-
詞法分析:分析器通過語法分析器,識別出了裏面的字符分別是什麼,代表着什麼。
比如上面例子中,會將select這個關鍵字識別出來,首先知道這是條查詢語句,然後把employee識別成表面employee,再把字符串salary識別成列ID,以此類推。最後識別出每個詞。
-
語法分析:根據詞法分析的結果,語法分析器會根據語法規則,判斷輸入的這個SQL語句是否滿足MySQL語法。如果發現不滿足,就會收到“you have an error in your SQL syntax”的錯誤提醒。
優化器
簡介:經過上面的分析器,MySQL知道了需要做什麼事兒了,但在開始做之前,還需要經過優化器的處理。
大概兩個優化
- 優化器在表裏面有多個索引時,決定使用哪個索引。
- 在一個語句有奪標關聯(join)的時候,決定各個表連接的順序。
選擇更快的索引好理解,稍微有點繞口的時決定各個表連接的順序。
舉個栗子
select * from a join b using(id) where a.c=10 and b.d=20;
這個關聯中
-
既可以先從表a中取出c=10的記錄的ID值,再根據ID值關聯到表b,再判斷b裏面d的值是否等於20。
-
也可以先從表b中取出d=20的記錄的ID值,再根據ID值關聯到表a,再判斷a裏面c的值是否等於10。
用不同的執行方法的邏輯結果是一樣的,但是執行的效率會有不同。優化器就會決定選擇使用哪一種方案,當然迴旋執行效率高的。
執行器
簡介:通過分析器知道了我是誰,我要幹什麼,通過優化器知道了我要怎麼幹我乾的事情。於是到了執行器階段,就要開始幹活啦!
當然也不是說幹就幹,人家還是很正經有流程的
- 1、判斷對這個表employee有沒有查詢的權限,如果沒有,那當然不行的了,會返回沒有權限的錯誤❌
- 2、要是判斷出來有權限呢,就會打開表繼續執行,打開的時候,執行器就會根據表的引擎定義,去使用這個引擎提供的接口。再提一嘴,默認引擎是InnoDB。然後就會順着下去,根據引擎提供的流程,執行下去,最後找到我們想要的。
至此,整個流程就結束了。