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

背景

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

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

Mysql基本架構圖

咱們先看下Mysql的一個較總體的架構圖。數據庫

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

客戶端

所謂客戶端,便是咱們登陸與操做Mysql所使用的終端。咱們都是在客戶端對Mysql進行操做的,不管是輸入鏈接數據庫的信息,仍是輸入查詢某個表的SQL,或者是收到Mysql返回給咱們的查詢信息,這些都是在客戶端完成的。架構

鏈接器

用戶信息驗證

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

咱們都知道,咱們要輸入命令mysql -h$ip -P$port -u$username -p3d

以後客戶端會要求咱們輸入密碼。再以後,若是咱們輸入的信息都沒有問題了,咱們就進入Mysql的操做界面了。code

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

那麼,這中間鏈接器具體作了什麼呢?對象

首先,鏈接器會拿着咱們輸入的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來查看當前全部的用戶鏈接及其行爲。

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

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

該超時時間由wait_timeout變量控制,能夠經過show global variables like 'wait_timeout'來查看。

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

長鏈接與短鏈接

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

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

長鏈接的優勢是,在持續操做時,能夠節省不少創建鏈接所須要消耗的時間。可是長鏈接所要存儲的臨時數據都在鏈接對象中,長時間積累,會致使系統內存溢出,具體表現 爲Mysql異常重啓。

短鏈接的優缺點與長鏈接相反,雖然不用擔憂內存溢出的問題,但短鏈接在持續操做的狀況下屢次鏈接,鏈接消耗不少時間,總體操做效率會很低。

緩存器

鏈接器鏈接完成的下一步就是緩存器的緩存查詢,若是咱們須要對一張靜態表(不常更新)常常作查詢操做,那麼可能會用到緩存器。

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

要注意的是,只要該表作了一次更新操做,那麼該表對應的緩存就會所有被清理。所以使用場景並很少。

因此當前緩存器的使用較少。咱們能夠經過query_cache_type來查看緩存器是否開啓。

如今通常都是默認關閉的狀態。且Mysql從8.0版本會開始完全棄用該功能。

分析器

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

那麼鏈接器作鏈接操做以後,接下來咱們就輸入了一個查詢語句,好比:SELECT host FROM mysql.user LIMIT 1

而分析器作的事情就是對你輸入的語句作 「詞法分析」「語法分析」

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

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

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

假如不符合語法規則,則分析器會返回報錯信息給客戶端。
具體出錯的地方,通常都是跟在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

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

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

而precheck是沒法對運行時涉及到的表進行權限驗證的,好比使用了觸發器的狀況。所以在執行器這裏也要作一次執行時的權限驗證。

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

總結

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

相關文章
相關標籤/搜索