面試官:你來講講一條查詢語句的具體執行過程

前言

對於一個開發工程師來說,瞭解一下 MySQL 是如何執行一條查詢語句的,是一件很有必要的事情,不僅對於工作上有幫助,面試的時候還不至於被面試官問倒!

下面我們來看看MySQL執行一條查詢語句的具體過程吧

一條看似非常簡單的查詢語句:

select * from T where id=1; 

然後 MySQL 就返回給了你結果,但是裏面具體是如何執行的呢?

首先咱們先來看一張圖,接下來的過程都是基於這張圖來講的:

面試官:你來講講一條查詢語句的具體執行過程

 

連接器

當客戶端連接 MySQL 時,會發出連接請求到連接器,連接器此時就會去驗證這個連接的賬號密碼

  • 如果賬號或者密碼不正確,客戶端就會收到一個 Access denied for user 的錯誤,之後此次連接結束
  • 賬號密碼正確,連接器會到權限表裏面查詢出該賬號所擁有的權限,之後這個連接裏面的權限判斷,都是以此時讀到的權限爲根據

所以你知道爲什麼更改了一個賬號的權限之後,一定要斷開再重連纔有效吧~

在實際中肯定有這樣的情況,就是一個連接建立之後,但是我沒有執行什麼操作,那麼就可以說這個連接處於空閒狀態( sleep )

如果長時間都沒有什麼操作的話,連接器就會選擇把它斷開,這個時間是由 wait_timeout 來控制的,默認值是 8 小時

連接都被斷開了,如果此時客戶端再次發送請求想要進行一些操作的話,那就需要重新建立連接才能往下走

在數據庫中有兩種連接:

  • 短連接:每次執行完很少的幾次查詢就斷開連接,下次想查詢時,就要重新建立一個
  • 長連接:如果客戶端持續有請求,那就一直使用同一個連接

建立連接是比較麻煩的,首先要發送請求吧,發送了請求要去驗證賬號密碼吧,驗證完了要去看你所擁有的權限吧,所以在使用過程中,儘量使用長連接

但是使用長連接又有新的問題:有時候,你會發現 MySQL 佔用內存,因爲是長連接嘛,所以它會在斷開的時候纔將資源釋放掉。

這個時候可以考慮下面兩種方案:

  • 定期斷開長連接
  • 如果使用的是 MySQL 5.7 或者更高版本,可以在每次執行一個比較大的操作之後,通過執行 mysql_reset_connection 來重新初始化連接資源,這個過程不需要重新連接和權限驗證

分析器

連接器這一關是過來了,接下來就是去查詢緩存

首先看緩存裏面有沒有,如果有呢,那就沒有必要向下走,直接返回給客戶端結果就可以了

如果緩存中沒有的話,那就去分析器

但是聰明的你肯定發現了,我的小標題並不是緩存,而是分析器,爲啥呢?

因爲查詢緩存的失效非常頻繁,只要有對一個表的更新,那在這個表上的所有查詢緩存都會被清空。所以就會導致 MySQL 費勁吧啦的把緩存給建立起來了,結果呢還沒怎麼用,一個更新操作,給弄沒了

所以 MySQL 8.0 版本直接將查詢緩存的整塊功能都給刪掉了,那麼在這裏也不細說,免得奇怪的知識增加

分析器首先會進行"詞法分析",詞法分析就是 select * from T where id=1; ,它會將 select 識別出來,哦,這是一個查詢語句,接下來會將 T 也識別出來,哦,你是想要在這個表中做查詢,然後將 where 後面的條件也識別出來,原來我需要去查找這些內容

OK ,“詞法分析”之後,接下來是“語法分析”,語法分析主要就是分析輸入的 SQL 語句合不合法

就比如英語裏面的語法 “我用 is , 你用 are ”這種,如果不對肯定是不可以的,語法分析之後發現你的 SQL 語句不符合規則,就會收到 You hava an error in your SQL syntax 的錯誤提示

優化器

經過分析器分析之後, MySQL 就知道你要的是什麼了

但是就像條條大路通羅馬一樣,看似是一條簡單的 SQL 查詢語句,有可能有好多條執行路徑可以走,比如說要查詢的表裏面有多個索引,我使用哪兒個索引效率會比較高呀;多表聯查的時候,我先關聯哪兒個表效率會比較高呀

像這種就是優化器需要做的事情

執行器

優化器做完優化之後,就到了執行器

執行器就是要去執行語句了嘛,那我肯定要看看對於要查詢的表 T 有沒有查詢權限,如果沒有直接就拒絕,這沒啥說的 如果有的話,那就會這樣(在這裏以 InnoDB 爲例):

  • 調用 InnoDB 引擎接口取這個表的第一行,判斷 ID 的值是不是 10 ,如果不是就跳過,如果是那就放在結果集中;
  • 調用引擎接口取“下一行”;重複相同的判斷邏輯,直到這個表的最後一行
  • 執行器將上述遍歷過程中所有滿足條件的行,組成記錄集返回給客戶端

至此,語句執行結束

存儲引擎

存儲引擎,一聽名字大概就能知道,它負責的是對數據的存儲和提取

關於存儲引擎這塊,最熟悉的應該就是 InnoDB 了,畢竟從 MySQL 5.5.5 版本開始它就成爲了默認的存儲引擎

舉個栗子

OK ,到這裏你可能就比較瞭解了,但是爲了讓大家理解的更深刻一些,這裏還準備了個栗子,咱們來瞅瞅:

select * from T where `name` = '張三' and age = '18' ; 

還記得MySQL 會怎麼做嗎?

  • 通過連接器查詢當前執行者的角色是否有權限,進行查詢。如果有的話,就繼續往下走,如果沒有的話,抱歉,哪怕是你貌美如花,也要拒絕掉,同時甩你一個 Access denied for user 的錯誤信息
  • 接下來就是分析器來分析語句了,嗯,你這個語句寫的沒啥問題,繼續向下執行吧
  • 此時來到了優化器,優化器就想,這條執行語句,有兩種執行方案啊:

先查詢表 T 中姓名爲 “張三”的,然後再判斷他年齡是不是 18 歲

先查詢表 T 中年齡爲 18 歲的所有人,然後再從裏面找到姓名爲“張三”的

  • 等優化器決定選擇哪個方案之後,執行器就去執行了。然後返回給客戶端結果

面試造火箭,工作擰螺絲,希望能幫助到你!

多多轉發讓更多人受益!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章