1. 程式人生 > 實用技巧 >SQL語句在MySQL中是如何執行的

SQL語句在MySQL中是如何執行的

參考:

https://mp.weixin.qq.com/s?__biz=MzU3NDkwMjAyOQ==&mid=2247483894&idx=1&sn=43642fac89173db293d2a3739decb4ef&chksm=fd2a1b94ca5d92822ac4a8b97c4cc1323255f366a2f0114de7ee9ba1faa58ba2a85195dd126b&scene=178&cur_album_id=1552870102100983810#rd

SQL語句在MySQL中是如何執行的

mysql> select * from T where ID=10;

開門見山,當我們輸入一條 SQL 語句的時候,MySQL 內部究竟執行了什麼?直接上架構圖,我們才能對其有一個概念,而不要陷入細節之中。

架構

架構概況

大體上來說,MySQL 可以分為 Server 層與儲存引擎兩個部分。

  1. Server 層包括聯結器、查詢快取、分析器、優化器、執行器。
  2. 儲存引擎負責資料的儲存和讀取,其架構模式是外掛式的,支援支援 InnoDB、MyISAM、Memory 等多個儲存引擎。現在最常用的儲存引擎是 InnoDB,它從 MySQL5.5.5 版本開始成為了預設儲存引擎。

所以不難看出,主要差別在於 Server 層,也就是聯結器到執行器部分。接下來我們來說明上文的 SQL 語句到底在內部經歷了什麼。

聯結器

第一步,客戶端會先連線到資料庫,這個時候就是聯結器來接待。它負責跟客戶端建立連線、獲取許可權、維持和管理連線。

如果使用者名稱密碼正確,聯結器就到許可權表查詢你所擁有的的許可權之後這個連線裡面的許可權判斷,都依賴於此時讀到的許可權。

這就意味著,一個使用者成功建立連線後,被修改了許可權,也不會影響已經存在的連線的許可權。修改完成後,只有再重新建立的連線才會使用到新的許可權設定。

建立連線的過程通常是比較複雜的,所以我建議你在使用中要儘量減少建立連線的動作,也就是儘量使用長連線。

查詢快取

連線建立好了以後,就可以執行 select 語句了,執行邏輯進入第二步:查詢快取。

MySQL 拿到一個查詢語句,會先查詢快取,先校驗這個語句是否執行過,以 key-value 的形式存在記憶體裡, Key 是查詢預計,Value 是結果集。如果快取 key 被命中,就會直接返回給客戶端,如果沒有命中,就會執行後續的操作,完成後也會把結果快取起來,方便下一次呼叫。當然在真正執行快取查詢的時候還是會校驗使用者的許可權,是否有該表的查詢條件。

Mysql 查詢不建議使用快取,因為對於經常更新的資料來說,快取的有效時間太短了,往往帶來的效果並不好,對於不經常更新的資料來說,使用快取還是可以的,Mysql 8.0 版本後刪除了快取的功能,官方也是認為該功能在實際的應用場景比較少,所以乾脆直接刪掉了。

分析器

如果沒有命中快取,那麼就進入分析器,主要就是分析 SQL 語句是拿來幹嘛,也就是解析該語句生成語法樹,會分為兩步:

  1. 第一步:詞法分析, 一條 SQL 語句有多個字串組成,首先要提取關鍵字,比如 select,提出查詢的表,提出欄位名,提出查詢條件等等。做完這些操作後,就會進入第二步。
  2. 第二步:語法分析,主要就是判斷你輸入的 SQL 是否正確,是否符合 MySQL 的語法。,主要就是判斷你輸入的 SQL 是否正確,是否符合 MySQL 的語法。

優化器

經過了分析器分析,MySQL 知道你要幹啥了,在開始執行之前,還要先經過優化器的處理。

優化器的作用就是它認為的最優的執行方案去執行(雖然有時候也不是最優),比如多個索引的時候該如何選擇索引,多表查詢的時候如何選擇關聯順序等。

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

比如這條語句,既可以先從表 t1 裡面取出 c=10 的記錄的 ID 值,再根據 ID 值關聯到表 t2,再判斷 t2 裡面 d 的值是否等於 20。也可以先從表 t2 裡面取出 d=20 的記錄的 ID 值,再根據 ID 值關聯到 t1,再判斷 t1 裡面 c 的值是否等於 10。

這兩種的執行邏輯結果是一樣的,但是執行效率會有不同,而優化器就是決定使用哪種方案。

執行器

當選擇了執行方案後,MySQL 就準備開始執行了,首先執行前會校驗該使用者有沒有許可權,如果沒有許可權,就會返回錯誤資訊,如果有許可權,就會去呼叫引擎的介面,返回介面執行的結果。這裡的許可權其實就是第一步客戶端連線到聯結器然後去查詢出來的許可權資訊。

InnoDB 引擎更新資料的操作其實還會涉及到兩個日誌模組的操作,以後會專門分析。主要就是 binlog 以及 redolog 的操作。

InnoDB 引擎把資料儲存在記憶體中,同時記錄 redo log,此時 redo log 進入 prepare 狀態,然後告訴執行器,執行完成了,隨時可以提交。執行器收到通知後記錄 binlog,然後呼叫引擎介面,提交 redo log 為提交狀態,更新完成。

總結

  • Mysql 主要分為 Server 層和引擎層,Server 層主要包括聯結器、查詢快取、分析器、優化器、執行器,同時還有一個日誌模組(binlog),這個日誌模組所有執行引擎都可以共用。
  • 引擎層是外掛式的,目前主要包括,MyISAM,InnoDB,Memory 等。
  • 查詢語句的執行流程如下:許可權校驗(如果命中快取)---》查詢快取---》分析器---》優化器---》許可權校驗---》執行器---》引擎 。
  • 更新語句執行流程如下:分析器----》許可權校驗----》執行器---》引擎---redo log(prepare 狀態---》binlog---》redo log(commit 狀態) 。

參考

《MySQL 專欄 45 講》