1. 程式人生 > 實用技巧 >MySQL 服務端整體架構和 SQL 查詢語句的執行流程

MySQL 服務端整體架構和 SQL 查詢語句的執行流程

MySQL 資料庫客戶端成功建立與服務端的連線和並完成使用者認證後,就可以傳送 SQL 語句與服務端互動了:

接下來,我們一起來探究當客戶端傳送一個 SQL 查詢語句後,服務端都做了哪些操作,將最終結果返回給客戶端。

服務端整體架構

開始之前,我們先來看看 MySQL 服務端的整體架構:

可以看到服務端主要由 Server 層和儲存引擎兩部分組成:

  • Server 層包括聯結器、查詢快取、分析器、優化器、執行器等,涵蓋 MySQL 的大多數核心服務功能,以及所有的內建函式,所有跨儲存引擎的功能都在這一層實現,比如儲存過程、觸發器、檢視等。
  • 儲存引擎層負責資料的儲存和提取,其架構模式是外掛式的,支援 InnoDB、MyISAM、Memory 等多個儲存引擎。現在最常用的儲存引擎是 InnoDB,它從 MySQL 5.5.5 版本開始成為了預設儲存引擎。我們後續教程也主要基於 InnoDB 進行講解。

對 MySQL 服務端架構有了整體瞭解後,接下來,我們來依次探究一條 SQL 查詢語句到達服務端後,在每個元件中都經歷了什麼。

由於現在客戶端已經建立了與服務端的連線,所以連機器這一步就可以跳過了,我們接著往下看。

查詢快取

當 MySQL 服務端拿到一條 SQL 查詢語句後,首先會查詢快取,看之前是不是執行過這條語句。如果執行過,會快取在記憶體中,這個時候直接返回之前快取的查詢結果給客戶端即可;如果在快取中沒有找到對應的記錄,就會繼續後面的操作,並且在最終執行完成後,將查詢結果儲存到查詢快取。

可以看到,如果命中查詢快取,MySQL 不需要執行後面的複雜操作就可以直接返回結果,查詢效率會很高。但是通常不建議這麼做,原因和是否要在業務邏輯中儲存模型類查詢結果一樣:因為這個快取的 key 是查詢語句,只要有一點不同(實際專案中查詢欄位、查詢條件千姿百態)就會導致快取命中失敗,同時,資料表記錄本身也是不斷更新(插入、更新、刪除)的,更新之後,之前的查詢快取就全部失效了,所以從維護成本和實際收益上看,得不償失。除非這張表建立初始化後不怎麼更新,是一個靜態表,並且查詢語句相對單一。

注:MySQL 8.0 版本開始將不再支援查詢快取功能。

你可以通過 show variables like '%query_cache%'; 語句檢視系統查詢快取設定:

query_cache_typeOFF 表示預設關閉。你可以在配置檔案中配置該值來決定是否啟用查詢快取。

分析器

如果查詢快取沒有啟用或者沒有命中,就開始真正執行 SQL 查詢語句了。

MySQL 會通過分析器對 SQL 語句做詞法分析,以確定到底要做什麼,比如 select 表示查詢語句,update 表示更新語句等,表名是什麼,查詢的欄位有哪些,查詢的條件是什麼。

確定要做的事情之後,分析器還會對 SQL 語句進行語法分析,以確保符合 MySQL 語法,你可能對 You have an error in your SQL syntax

這個報錯很熟悉,這就是 SQL 語句語法錯誤的提示(重點關注「use near」後面的錯誤原因):

優化器

如果 SQL 語句詞法和語法分析都沒有問題,接下來,會經由優化器生成執行計劃,這裡面主要的工作是資料表包含索引的時候,判定是否使用索引,以及使用哪些索引效率最高(掃描行數最少),我們可以在執行一個 SQL 查詢語句之前通過 explain 語句檢視它的執行計劃:

注:關於返回結果欄位的解釋我們在後面會專門介紹,這裡先了解即可。

執行器

通過分析器可以知道客戶端傳送的 SQL 語句要做什麼,通過優化器可以確定要怎麼做,最後就是真正去執行了,這一步通過服務端的執行器完成。

在根據執行計劃執行 SQL 查詢語句時,會先驗證許可權,有相應的許可權才會繼續執行,否則會報許可權錯誤。

在具體執行查詢操作時,是通過呼叫儲存引擎提供的 API 介面完成的,MySQL 支援不同的儲存引擎,雖然這些儲存引擎存取資料的底層實現不盡相同,但是對 Server 層提供了統一的介面,執行器呼叫這些介面可以完成諸如讀取下一行記錄、插入記錄、更新記錄之類的日常資料庫操作,執行 SQL 查詢返回所有滿足條件的結果集也是如此。

在儲存引擎中進行查詢操作時,如果 SQL 語句沒有使用索引,則需要一條條遍歷資料表的所有記錄(全表掃描),然後將滿足條件的記錄存放到結果集,直到資料表最後一行,最後再把這個結果集返回給客戶端。如果資料表非常大,表記錄非常多時,這種查詢的效率會很低下,這是我們在優化資料庫查詢效率時所要極力避免的現象。

反之,如果 SQL 查詢語句中使用了索引,則可以極大提升查詢效率,至於底層的原因,我們後面介紹儲存引擎底層實現和索引時,會專門進行介紹。