每天都在跟 mysql 打交道,你知道執行一條簡單的 select 語句,都經歷了哪些過程嗎?
首先,mysql 主要是由 server 層和儲存層兩部分構成的。server 層主要包括聯結器、查詢快取,分析器、優化器、執行器。儲存層主要是用來儲存和查詢資料的,常用的儲存引擎有 InnoDB、MyISAM,MySQL 5.5.5版本後使用 InnoDB 作為預設儲存引擎。
聯結器
聯結器主要負責將 mysql 客戶端和服務端建立連線,連線成功後,會獲取當前連線使用者的許可權。這裡獲取到的許可權對整個連線都有效,一旦連線成功後,如果使用管理員賬號對該使用者更改許可權,當前連線中的擁有的許可權保持不變,只有等到下次重新連線才會更新許可權。
查詢快取
連線成功後,即開始要正式執行 select 語句了,但是在執行查詢之前,mysql 會去看下有沒有該條語句的快取內容,如果有快取直接從快取中讀取並返回資料,不再執行後面的步驟了,結束查詢操作。
如果沒有快取則繼續往後執行,並將執行結果和語句儲存在快取中。
注意在 mysql8 後已經沒有查詢快取這個功能了,因為這個快取非常容易被清空掉,命中率比較低。只要對錶有一個更新,這個表上的所有快取就會被清空,因此你剛快取下來的內容,還沒來得及用就被另一個更新給清空了。
分析器
既然沒有查到快取,就需要開始執行 sql 語句了,在執行之前肯定需要先對 sql 語句進行解析。分析器主要對 sql 語句進行語法和語義分析,檢查單詞是否拼寫錯誤,還有檢查要查詢的表或欄位是否存在。
如果分析器檢測出有錯誤就會返回類似 "You have an error in your sql" 這樣的錯誤資訊,並結束查詢操作。
優化器
通過分析器之後,mysql 就算是理解了你要執行的操作了。通常對於同一個 sql 語句,mysql 內部可能存在多種執行方案,比如存在多個索引時,該選擇哪個索引,多個表關聯查詢時,怎麼確認各個表的連線順序。
這些方案的執行結果都一樣,但是執行效率不一樣,所以 mysql 在執行之前需要嘗試找出一個最優的方案來,這就是優化器的主要工作。但是 mysql 也會有選擇錯誤方案的時候,這裡暫不細說,留到後面再解釋原因。
執行器
經過優化器選定了一個方案後,執行器就按照選定的方案執行 sql 語句。前面我們有講過,在聯結器中會讀取當前使用者的許可權,聯結器中只是獲取許可權而已,並沒有對許可權進行判斷和校驗。
所以在執行器中,在執行語句之前會判斷許可權,如果沒有對應的許可權則會直接返回並提示沒有相關許可權。
這裡你可能會問,為什麼不在聯結器中就直接判斷許可權呢,這裡我覺得可能是因為 mysql 要查詢的表並不一定僅限於 sql 語句中字面上的那些表,有的時候可能需要經過分析器和優化器之後才能確定到底要怎麼執行,所以許可權校驗放在執行器中是有道理的。
注意如果是在前面的查詢快取中查到快取之後,也會在返回結果前做許可權校驗的。
許可權校驗通過之後,就繼續開啟表,呼叫儲存引擎提供的介面去查詢並返回結果集資料。
到這裡,一條查詢 sql 語句就執行結束了。講的比較粗糙,只是一個大致的流程,其中每一步在 mysql 的底層實現都非常複雜,後面再講一講索引的底層實現原理。