MySQL邏輯架構:一條SQL查詢語句是如何執行的?

首先咱們來了解 MySQL 的邏輯架構,對 MySQL 有一個總體的認識。mysql

例如在執行下面的一條語句時:sql

mysql> select * from T where ID=10;

咱們看到的結果是返回一條記錄,那麼 MySQL 是如何執行這條 SQL 查詢語句呢?緩存

首先咱們來看一下 MySQL 的邏輯架構圖:架構

大致來講,MySQL 分爲 Server 層和存儲引擎層兩部分。優化

Server 層包含鏈接器、查詢緩存、分析器、優化器、執行器等 MySQL 的核心服務功能。插件

存儲引擎層負責數據的存儲和提取。其架構是插件式的,支持 InnoDB、MyISAM、Memory 等多種存儲引擎。code

從圖中不難看出,不一樣的存儲引擎共用一個 Server 層。下面咱們經過上面那條 SQL 查詢語句來看一下總體流程和每一個組件的做用。server

鏈接器

鏈接器是客戶端與 MySQL 進行鏈接的組件。客戶端經過如下命令進行鏈接:blog

mysql -h$ip -P$port -u$user -p

輸完這條命令後,再輸入用戶名和密碼。雖然也可以在上面的命令裏同時輸入密碼,但容易形成密碼泄露,尤爲是在生產環境中,不建議把密碼顯式輸入。索引

  • 若是用戶名或密碼不正確,返回 "Access denied for user" 的錯誤,鏈接中斷。
  • 若是用戶名密碼認證經過,鏈接器會到權限表中查出你的權限,以後這個鏈接的權限判斷都依賴於讀取出來的權限。

這意味着,一個用戶成功創建鏈接後,即使修改了他的權限,當前鏈接也不會生效,除非斷開重連。

查詢緩存

上一步與 MySQL 創建了鏈接,而後咱們從客戶端輸入 SQL 查詢語句:

mysql> select * from T where ID=10;

MySQL 會先到查詢緩存裏找,看是否存在這條記錄。若是存在,則直接返回結果。

可是大多數狀況下我會建議你不要使用查詢緩存,爲何呢?由於查詢緩存每每弊大於利。

查詢緩存裏的緩存數據很容易失效,只要表中任意數據的更新都會清空這個表的緩存,尤爲是對於寫比較頻繁的應用,緩存基本不起效果。

咱們能夠經過把參數 query_cache_type 設置成 DEMAND 來禁用查詢緩存,也能夠顯式設置使用查詢緩存:

mysql> select SQL_CACHE * from T where ID=10;

注意:MySQL 8.0 版本直接將查詢緩存的整塊功能刪掉了,也就是說 8.0 開始完全沒有這個功能了。

分析器

MySQL 是如何 「認得出」 這條 SQL 語句的呢?

經過分析器,MySQL 首先對 SQL 語句進行詞法分析,提取爲若干個字符串。

而後再進行語法分析,判斷 SQL 語句是否符合 MySQL 的語法。

若是你的語句不對,就會收到 「You have an error in your SQL syntax」 的錯誤提醒,好比下面這個語句 select 少打了開頭的字母 「s」 。

mysql> elect * from t where ID=1;

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'elect * from t where ID=1' at line 1

通常語法錯誤會提示第一個出現錯誤的位置,因此你要關注的是緊接 「use near」 的內容。

優化器

通過分析器,MySQL 知道了要作什麼,在開始執行前,還須要通過優化器的處理。

優化器是在表裏有多個索引時,決定使用哪一個索引。好比下面的查詢語句:

mysql> select * from t1 join t2 using(ID)  where t1.c=10 and t2.d=20;

有兩種執行方式:

  1. 先從表 t1 裏讀取 t1.c=10 的行,而後再從表 t2 裏判斷 t1.ID=t2.ID and t2.d=20
  2. 先從表 t2 裏讀取 t2.d=20 的行,而後再從表 t1 裏判斷 t1.ID=t2.ID and t1.c=10

優化器就是判斷要選擇哪一種執行方式,大概的判斷依據是 「成本估算」,估算哪一種執行方式的 「成本」 更低,就選擇哪一種。

執行器

MySQL 通過分析器知道要作什麼,通過優化器知道怎麼作,最後就是執行了。首先 MySQL 會判斷是否具備查詢權限,若是沒有,就返回沒有權限的錯誤,以下:

mysql> select * from T where ID=10;

ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'

若是有權限,就打開表繼續執行。打開表的時候,執行器會根據表中定義的存儲引擎,去使用這個存儲引擎提供的接口。

好比咱們的例子中,表 T 中,ID 字段沒有索引,那麼執行器的流程是:

  1. 調用 InnoDB 存儲引擎接口取一行,判斷 ID=10。若是不是,則跳過;如是,則保存到結果集中。
  2. 而後再取下一行,重複直到表結束爲止。
  3. 最後組成結果集返回給客戶端。

參考資料

相關文章
相關標籤/搜索