天天看點

京東一面:說一下SQL查詢語句的執行過程

作者:尚矽谷教育

我們在項目中避免不了要與資料庫互動,那麼一條SQL語句是如何執行的呢?這篇文章我們就來聊聊MySQL的基礎架構。

一、MySQL 邏輯架構概覽

在執行下面這個查詢語句時:

select * from user where id = 10 ;

看到的隻是輸入一條SQL語句,傳回一個結果,卻不知道這條語句在MySQL内部的執行過程。

接下來就把MySQL拆解一下,讓大家看看裡面都有哪些“零件”。下面是MySQL的基本架構示意圖:

京東一面:說一下SQL查詢語句的執行過程

MySQL的邏輯架構圖

總的來說,MySQL可以分為Server層和存儲引擎兩部分。

Server層:

Server層包括連接配接器、查詢緩存、分析器、執行器等,包含了MySQL的大多數核心功能,還有内置函數(如日期、時間、數學和加密函數等)。

存儲引擎層:

存儲引擎層負責資料的存儲和提取。其架構模式是插件式的,支援MyISA、MInnoDB等多個存儲引擎。現在最常用的是InnoDB,從MySQL5.5.5版本開始預設的存儲引擎就是InnoDB。在執行create table建表的時候不指定引擎類型的話,預設使用的就是InnoDB。注意

注意:

在MySQL5.1及以前的版本,使用的預設存儲引擎是MyISAM。

二、連接配接器

連接配接器一般會做兩件事,一個是管理MySQL連接配接,一個是權限驗證。下面來依次說明。

管理MySQL連接配接:

我們通常在連接配接MySQL伺服器的時候要輸入使用者名和密碼,如果是其他機器還需要輸入指定的主機IP。連接配接指令:mysql -h ip -P port -u user -p

如果使用者名和密碼不正确,連接配接器就會傳回錯誤資訊“Access denied for user”。

權限驗證:

如果使用者名和密碼認證通過了,連接配接器就會查詢權限表裡的權限。之後,這個連接配接裡面的所有權限判斷邏輯,都将依賴于此時讀到的權限。

也就是說,當一個連接配接建立後,即使你在其他連接配接裡修改了這個賬戶的權限,也不會對目前這個連接配接的權限造成任何影響。隻有重建立立連接配接才會擷取新的權限。

連接配接完成後,如果長時間沒有操作,就會處于空閑狀态。實際上對于一個MySQL連接配接來說,任意一時刻都有一個狀态,可以使用“SHOW FULL PROCESSLIST”指令檢視。如下圖所示:

京東一面:說一下SQL查詢語句的執行過程

Command 列就表示目前的狀态。

用戶端如果太長時間沒有動靜,連接配接器就會自動将它斷開。這個時間是由參數 wait_timeout 控制的,預設值是8小時。可用指令檢視:"show variables like 'wait_timeout';",如下圖:

京東一面:說一下SQL查詢語句的執行過程

三、查詢緩存

連接配接建立完成後,就可以輸入查詢語句進行查詢了。執行邏輯來到第二步:查詢緩存。

1. 當MySQL拿到查詢請求後,首先會到緩存中去看,之前是否執行過這條語句。如果目前查詢正好命中查詢緩存,那麼緩存的值就會直接傳回給用戶端。

2. 如果語句不在緩存中,就會繼續後面的執行階段。執行完成後,執行結果會被存入查詢緩存中。

3. 但是大多數情況下不建議使用查詢緩存,因為既然涉及到緩存,就必然繞不開緩存一緻性問題。

4. 值得慶幸的是,不需要我們進行額外操作,查詢緩存并不會傳回陳舊資料。當表被修改時,查詢緩存中的任何相關條目都會被 flushed。

5. 對于MySQL8.0之前的版本,可以将參數“query_cache_type” 設定成 DEMAND,這樣對于預設的 SQL 語句都不使用查詢緩存。而對于你确定要使用查詢緩存的語句,可以用 SQL_CACHE 顯式指定,像下面這個語句一樣:

mysql> select SQL_CACHE * from user where id = 1 ;

注意:

1.這裡的 flushed 翻譯為清空而不是重新整理。

2.從 MySQL 5.7.20 開始,官方不再推薦使用查詢緩存,并在 MySQL 8.0 中直接删除了查詢緩存!

四、分析器

如果沒有命中緩存或者查詢緩存沒有開啟,就要開始真正的執行語句了。

1. 分析器先會做“詞法分析”,輸入的SQL語句是多個字元串組成,MySQL需要識别裡面的字元串分别是什麼,代表什麼。

2. 做完識别後緊接着就要做文法分析了。根據詞法分析的結果,文法分析器會根據文法規則,判斷這個SQL語句是否滿足MySQL文法。

3. 分析器會根據SQL語句生成一個資料結構——解析樹。如下圖:

京東一面:說一下SQL查詢語句的執行過程

注意:

如果文法不對,就會收到“You have an error in your SQL syntax”的錯誤提醒。

五、優化器

解析樹是合法的,MySQL就知道了要幹什麼。但是一條SQL語句有很多種執行計劃,最終的傳回結果都相同。是以還需要優化器處理,選擇那種執行計劃。

優化器是在表裡有多個索引的時候,決定使用哪個索引。或者說一個語句有多個表關聯的時候,決定各個表的連接配接順序。

舉個例子:

select * from t1 where id = 10 and name = "good";

對于上面這個語句,可以先查找 name = good 在查找 id = 10 ,反之也行。但是這兩種執行計劃花費的時間成本是不一樣的。

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

優化器階段結束之後,這個語句的執行計劃就确定下來了,就可以進入執行器階段了。

六、執行器

MySQL 通過分析器知道了你要做什麼,通過優化器知道了該怎麼做,于是就進入了執行器階段,開始執行語句。

1. 執行的時候和查詢緩存的時候一樣,在執行SQL語句之前會判斷目前使用者是否有權限操作這張表,如果沒有,就會傳回沒有權限的錯誤。

2. 權限認證後MySQL會根據執行計劃給出的指令逐漸執行。打開表的時候,執行器就會根據表的引擎定義,去使用這個引擎提供的接口。

舉例:

mysql> select * from user where id = 10;

假設這個例子的user表中,id字段沒有索引,流程如下:

1.調用 InnoDB 引擎接口取這個表的第一行,判斷 id 值是不是 10,如果不是則跳過,如果是則将這行存在結果集中。

2.調用引擎接口取“下一行”,重複相同的判斷邏輯,直到取到這個表的最後一行。

3.執行器将上述周遊過程中所有滿足條件的行組成的記錄集作為結果集傳回給用戶端。

至此,這個語句就執行完成了。

七、總結

至此關于SQL查詢語句完整的執行流程的各個階段介紹完了,基本的執行順序就是“用戶端->連接配接器->查詢緩存->分析器->優化器->執行器”(MySQL8.0版本沒有查詢緩存)。優化器會改寫SQL,包括join的連接配接順序,比對索引,确定最優的SQL執行政策。相信大家對SQL的執行過程也有了基本的認識,最後再回歸一下流程圖:

京東一面:說一下SQL查詢語句的執行過程

繼續閱讀