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

2021-10-03 22:44:14 字數 3852 閱讀 3446

我們都經常使用mysql作為資料庫來儲存與查詢較常用的資料。當我們輸入一行如select * from table_name where id=26這樣的語句之後,mysql如果正確執行的情況下,會輸出你想要的資訊。

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

我們先看下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來檢視當前所有的使用者連線及其行為。

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),分別是連線、分析、優化與執行。每一步都會精確執行,如果發現有問題就會返回給客戶端相應的報錯。只有每一步都正確執行,最終才會在客戶端得到你想要查詢或操作的結果。

一條sql語句在mysql中如何執行的

1.1 mysql 基本架構概覽 下圖是 mysql 的乙個簡要架構圖,從下圖你可以很清晰的看到使用者的 sql 語句在 mysql 內部是如何執行的。先簡單介紹一下下圖涉及的一些元件的基本作用幫助大家理解這幅圖,在 1.2 節中會詳細介紹到這些元件的作用。查詢快取 執行查詢語句的時候,會先查詢快取...

一條SQL語句在MySQL中如何執行的

本篇文章會分析乙個 sql 語句在 mysql 中的執行流程,包括 sql 的查詢在 mysql 內部會怎麼流轉,sql 語句的更新是怎麼完成的。在分析之前我會先帶著你看看 mysql 的基礎架構,知道了 mysql 由那些元件組成以及這些元件的作用是什麼,可以幫助我們理解和解決這些問題。1.1 m...

一條 SQL 語句在 MySQL 中如何執行的

下圖是 mysql 的乙個簡要架構圖,從下圖你可以很清晰的看到使用者的 sql 語句在 mysql 內部是如何執行的。先簡單介紹一下下圖涉及的一些元件的基本作用幫助大家理解這幅圖,在 1.2 節中會詳細介紹到這些元件的作用。查詢快取 執行查詢語句的時候,會先查詢快取 mysql 8.0 版本後移除,...