1. 程式人生 > >MySQL系列:一句SQL,MySQL是怎麼工作的?

MySQL系列:一句SQL,MySQL是怎麼工作的?

對於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就執行完成了