對於MySQL而言,其實分為客戶端與服務端。 服務端,就是MySQL應用,當我們使用net start mysql命令啟動的服務,其實就是啟動了MySQL的服務端。 客戶端,負責發送請求到服務端並從服務端獲取數據,客戶端可以有多種形式,可以是我們通過mysql uroot p1234打開的黑視窗,也 ...
對於MySQL而言,其實分為客戶端與服務端。
服務端,就是MySQL應用,當我們使用net start mysql命令啟動的服務,其實就是啟動了MySQL的服務端。
客戶端,負責發送請求到服務端並從服務端獲取數據,客戶端可以有多種形式,可以是我們通過mysql -uroot -p1234打開的黑視窗,也可以是我們使用的Nativecat、SQLyog等資料庫連接工具,甚至我們的程式,也可以稱作MySQL的客戶端。
而當我們在mysql視窗或者資料庫連接工具中輸入一句sql後,我們就可以獲取到想要的數據,這中間MySQL到底是怎麼工作的呢?
在我們執行SQL後,例如一句簡單的select * from user where name = ‘yanger’,客戶端發送請求到服務端,請求到達Server層,會經過連接器、查詢緩存、分析器、優化器、執行器等,最終通過存儲引擎從文件系統獲取數據或者插入數據到文件系統。
連接器
在客戶端程式發起連接的時候,需要攜帶主機信息、用戶名、密碼,伺服器程式會對客戶端程式提供的這些信息進行認證,如果認證失敗,伺服器程式會拒絕連接。
連接命令大家都比較熟悉。
mysql -h$ip -P$port -u$user -p
輸完命令之後,需要繼續輸入密碼,密碼也可以直接跟在 -p 後面,但這樣可能會導致你的密碼泄露,如果你連的是生產伺服器,強烈建議你不要這麼做。
MySQL採用TCP作為伺服器和客戶端之間的網路通信協議,完成 TCP 握手後,連接器主要做密碼校驗和許可權獲取。
如果用戶名或密碼不對,你就會收到一個"Access denied for user"的錯誤
如果用戶名密碼認證通過,連接器會到許可權表裡面查出你擁有的許可權。之後,這個連接裡面的許可權判斷邏輯,都將依賴於此時讀到的許可權
MySQL的預設連接是8小時,由參數 wait_timeout 控制的,如果超過這個時間不使用,會自動斷開,併在之後的操作中,拋出Lost connection to MySQL server during query的錯誤。
查詢緩存
針對於查詢語句,MySQL 拿到一個查詢請求後,會先到查詢緩存看看,之前是不是執行過這條語句,之前執行過的語句及其結果可能會以 key-value 對的形式,被直接緩存在記憶體中。如果命中緩存,將直接返回結果。如果不在查詢緩存中,就會繼續後面的執行階段。執行完成後,執行結果會被存入查詢緩存中。
針對於更新語句,包含插入刪除語句,MySQL 收到更新請求時,會把查詢緩存中該表相關的緩存數據全部清空。
我們可以看到,只要有更新,緩存就會失效,而對於正常的業務,更新其實是比較頻繁的,也就是說,其實MySQL的查詢緩存命中率並不會很高,所以建議一般不到開啟。
可以通過設置 query_cache_type 為 DEMAND 來關閉查詢緩存功能。而事實上,在 MySQL 8.0 版本,更是直接移除了查詢緩存這一個功能。
分析器
MySQL 首先需要對SQL語句進行分析,分析過程本質上算是一個編譯過程,涉及詞法解析、語法分析、語義分析等階段,通過分析MySQL知道自己要做什麼。
如果語句不對,就會收到“You have an error in your SQL syntax”的錯誤提醒,一般語法錯誤會提示第一個出現錯誤的位置,所以你要關註的是緊接“use near”的內容。
優化器
面對分析器拿到的結果,MySQL會做一些優化處理,例如在表裡面有多個索引的時候,決定使用哪個索引,或者在一個語句有多表關聯(join)的時候,決定各個表的連接順序。
優化的結果就是生成一個執行計劃,這個執行計劃表明瞭應該使用哪些索引進行查詢,表之間的連接順序是啥樣的。我們可以使用EXPLAIN語句來查看某個語句的執行計劃。
這裡\G在命令視窗無法一行時,可以豎著展示結果,方便查看。
執行器
經過了分析器和優化器,就正式進行執行階段了,不過執行之前,需要做許可權驗證,如果許可權不足,就會拋出許可權的錯誤。其實在查詢緩存的時候,一樣也會進行許可權校驗。
如果通過驗證,執行器就打開表繼續執行。打開表的時候,執行器就會根據表的引擎定義,去使用這個引擎提供的介面。
存儲引擎
MySQL支持非常多種存儲引擎,常用的是InnoDB和MyISAM,MySQL的預設存儲引擎是InnoDB。
假如我們選擇是InnoDB引擎,對於查詢,那InnoDB 會取這個表的第一行來進行判斷是不是符合要求,符合則存在結果集中,否則繼續進行下一行,直到該表的最後一行。
然後存儲引擎將結果返回給執行器, 執行器拿著結果返回給客戶端,這樣一句SQL就執行完成了。