在Mysql中執行一條SQL,會怎樣?

前言

我們都經常使用Mysql作爲數據庫來存儲與查詢較常用的數據。當我們輸入一行如SELECT * FROM table_name WHERE id=26這樣的語句之後,Mysql如果正確執行的情況下,會輸出你想要的信息。

那麼,在你輸入這行語句之後,一直到它顯示出你想要的信息,這中間Mysql都經歷了什麼呢?這篇文章會簡單聊一下這個事情。

Mysql基本架構圖

我們先看下Mysql的一個較整體的架構圖。

接下來我會以具體的SQL語句爲例,詳細的敘述從你在客戶端輸入了這個語句之後,到它返回你想要的信息,這中間具體經歷了什麼。

 

在Mysql中執行一條SQL,會經歷什麼?

 

 

客戶端

所謂客戶端,即是我們登錄與操作Mysql所使用的終端。我們都是在客戶端對Mysql進行操作的,無論是輸入連接數據庫的信息,還是輸入查詢某個表的SQL,或者是收到Mysql返回給我們的查詢信息,這些都是在客戶端完成的。

連接器

用戶信息驗證

我們在一個客戶端跟前,想要使用Mysql數據庫,那麼第一步就是要先連接上你要使用的數據庫。

我們都知道,我們要輸入命令mysql -h$ip -P$port -u$username -p。

之後客戶端會要求我們輸入密碼。再之後,如果我們輸入的信息都沒有問題了,我們就進入Mysql的操作界面了。

如果我們輸入的信息有問題,就會收到客戶端返回的報錯信息。比如我們將密碼輸入錯誤了,這時就會收到"Access denied for user"這樣的報錯信息。

那麼,這中間連接器具體做了什麼呢?

首先,連接器會拿着我們輸入的IP和端口,去做最經典的TCP握手,握手如果都失敗了,那就自然沒有後續了,直接返回相應的報錯信息。

如果握手成功了,此時則會去驗證我們輸入的用戶名和密碼,驗證失敗則同樣會返回相應的報錯信息。

用戶權限獲取

如果用戶名密碼也沒有問題,接下來連接器則會取出權限表讀取該用戶相應的權限數據。用戶跟着所做的所有操作,都基於此時讀取到的用戶權限。

權限表共有4個:user, db, tables_priv, columns_priv。

當用戶通過權限驗證,進行權限分配時,按照user, db, tables_priv, columns_priv的順序進行分配。即先檢查用戶的全局權限表user,如果user中對應的權限爲Y,則此用戶對所有數據庫的權限都爲Y,將不再檢查剩餘3個表;如果爲N,則到db表中檢查此用戶對應的具體數據庫,並得到db中爲Y的權限;如果db中爲N,則檢查tables_priv中此數據庫對應的具體表,取得表中的權限Y;如果爲N,則到columns_priv中檢查具體的列。

這也就意味着,當我們修改了某個用戶的用戶權限,只有到下一次該用戶登錄(創建新的連接)時,纔會影響到該用戶。

連接與等待超時

我們可以通過show processlist來查看當前所有的用戶連接及其行爲。

在Mysql中執行一條SQL,會經歷什麼?

 

Command中的字段顯示該用戶目前的狀態,此時這個用戶是查詢狀態。

 

但若Command顯示的狀態是Sleep,那麼說明該用戶當前在等待狀態。若等待超過了一段時間,則連接器會自動斷開。

該超時時間由wait_timeout變量控制,可以通過show global variables like 'wait_timeout'來查看。

在Mysql中執行一條SQL,會經歷什麼?

 

mysql默認爲28800秒,即8小時。

 

長連接與短連接

所謂長連接,即用戶的持續操作使用的都是同一個連接,連接在一段時間內長時間建立。

所謂短連接,即用戶每做幾次操作則斷開,再下次操作時再進行連接。

長連接的優點是,在持續操作時,可以節省很多建立連接所需要消耗的時間。但是長連接所要存儲的臨時數據都在連接對象中,長時間積累,會導致系統內存溢出,具體表現 爲Mysql異常重啓。

短連接的優缺點與長連接相反,雖然不用擔心內存溢出的問題,但短連接在持續操作的情況下多次連接,連接消耗很多時間,整體操作效率會很低。

緩存器

連接器連接完成的下一步就是緩存器的緩存查詢,如果我們需要對一張靜態表(不常更新)經常做查詢操作,那麼可能會用到緩存器。

緩存器中使用的是key-value的存儲形式,key值存儲的是查詢語句,value值存儲的是對應結果。

要注意的是,只要該表做了一次更新操作,那麼該表對應的緩存就會全部被清理。因此使用場景並不多。

所以當前緩存器的使用較少。我們可以通過query_cache_type來查看緩存器是否開啓。

在Mysql中執行一條SQL,會經歷什麼?

 

現在一般都是默認關閉的狀態。且Mysql從8.0版本會開始徹底棄用該功能。

 

分析器

假設我們不使用緩存器,或者通過緩存器沒有命中SQL語句。

那麼連接器做連接操作之後,接下來我們就輸入了一個查詢語句,比如:SELECT host FROM mysql.user LIMIT 1。

而分析器做的事情就是對你輸入的語句做 “詞法分析” 與 “語法分析”

所謂 “詞法分析” ,就是判斷每一個你輸入的詞,比如分析器首先會判斷出你輸入的第一個詞是“SELECT”,第二個詞你輸入了“host”,等等。

而 “語法分析” 則是跟在 “詞法分析” 之後,就是依據你輸入的這些詞來判斷你輸入的是否符合語法規則。

假如符合語法規則,則會順利進行下去並返回相應信息。

在Mysql中執行一條SQL,會經歷什麼?

 

假如不符合語法規則,則分析器會返回報錯信息給客戶端。

在Mysql中執行一條SQL,會經歷什麼?

 

具體出錯的地方,一般都是跟在use near之後,我們看這裏就能知道語法錯誤出在了哪一塊。

 

優化器

在分析器工作結束後,如果語法有問題,那麼就會直接返回報錯信息,且不繼續向下運行。

若語法正確,那麼,則會到優化器部分的工作。優化器顧名思義,就是對該語句的執行做優化。

比如,在一個語句查詢某個表時,該表可能有多個索引,此時使用哪個索引會使語句的執行效率最高?這就是優化器要做的事情。

再比如,執行語句select * from t1 join t2 on t1.ID=1 and t2.ID=2,

該語句執行時,是先從t1表中找到ID=1的行關聯到t2表之後,再從t2表中查找ID=2的行。

還是先從t2表中找到ID=2的行關聯到t1表之後,再從t1表中查找ID=1的行。

兩種執行順序可能就導致執行效率的不同,怎樣選擇執行順序會提高執行效率,這也是優化器要做的事情。

執行器

在上述步驟完成之後,就輪到執行器去執行具體的語句了。

例如語句:select * from mysql.tables_priv

在執行器做具體的語句執行之前,會對該表的操作權限進行驗證,驗證失敗則返回權限錯誤的報錯。如下:

在Mysql中執行一條SQL,會經歷什麼?

 

而實際上,權限驗證不僅僅在執行器這部分會做,在分析器之後,也就是知道了該語句要“幹什麼”之後,也會先做一次權限驗證。叫做precheck。

 

而precheck是無法對運行時涉及到的表進行權限驗證的,比如使用了觸發器的情況。因此在執行器這裏也要做一次執行時的權限驗證。

如果驗證成功,那麼則會使用該表對應的存儲引擎的接口,繼續執行語句。 最後將成功執行的結果返回給客戶端。

總結

簡單來說,一條SQL語句在Mysql中執行,一共會經歷四步(算上連接Mysql),分別是連接、分析、優化與執行。每一步都會精確執行,如果發現有問題就會返回給客戶端相應的報錯。只有每一步都正確執行,最終纔會在客戶端得到你想要查詢或操作的結果。

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