咱們都常用Mysql做爲數據庫來存儲與查詢較經常使用的數據。當咱們輸入一行如SELECT * FROM table_name WHERE id=26
這樣的語句以後,Mysql若是正確執行的狀況下,會輸出你想要的信息。mysql
那麼,在你輸入這行語句以後,一直到它顯示出你想要的信息,這中間Mysql都經歷了什麼呢?這篇文章會簡單聊一下這個事情。sql
咱們先看下Mysql的一個較總體的架構圖。數據庫
接下來我會以具體的SQL語句爲例,詳細的敘述從你在客戶端輸入了這個語句以後,到它返回你想要的信息,這中間具體經歷了什麼。緩存
所謂客戶端,便是咱們登陸與操做Mysql所使用的終端。咱們都是在客戶端對Mysql進行操做的,不管是輸入鏈接數據庫的信息,仍是輸入查詢某個表的SQL,或者是收到Mysql返回給咱們的查詢信息,這些都是在客戶端完成的。架構
咱們在一個客戶端跟前,想要使用Mysql數據庫,那麼第一步就是要先鏈接上你要使用的數據庫。優化
咱們都知道,咱們要輸入命令mysql -h$ip -P$port -u$username -p
。3d
以後客戶端會要求咱們輸入密碼。再以後,若是咱們輸入的信息都沒有問題了,咱們就進入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顯示的狀態是Sleep,那麼說明該用戶當前在等待狀態。若等待超過了一段時間,則鏈接器會自動斷開。
該超時時間由wait_timeout變量控制,能夠經過show global variables like 'wait_timeout'
來查看。
所謂長鏈接,即用戶的持續操做使用的都是同一個鏈接,鏈接在一段時間內長時間創建。
所謂短鏈接,即用戶每作幾回操做則斷開,再下次操做時再進行鏈接。
長鏈接的優勢是,在持續操做時,能夠節省不少創建鏈接所須要消耗的時間。可是長鏈接所要存儲的臨時數據都在鏈接對象中,長時間積累,會致使系統內存溢出,具體表現 爲Mysql異常重啓。
短鏈接的優缺點與長鏈接相反,雖然不用擔憂內存溢出的問題,但短鏈接在持續操做的狀況下屢次鏈接,鏈接消耗不少時間,總體操做效率會很低。
鏈接器鏈接完成的下一步就是緩存器的緩存查詢,若是咱們須要對一張靜態表(不常更新)常常作查詢操做,那麼可能會用到緩存器。
緩存器中使用的是key-value的存儲形式,key值存儲的是查詢語句,value值存儲的是對應結果。
要注意的是,只要該表作了一次更新操做,那麼該表對應的緩存就會所有被清理。所以使用場景並很少。
因此當前緩存器的使用較少。咱們能夠經過query_cache_type
來查看緩存器是否開啓。
假設咱們不使用緩存器,或者經過緩存器沒有命中SQL語句。
那麼鏈接器作鏈接操做以後,接下來咱們就輸入了一個查詢語句,好比:SELECT host FROM mysql.user LIMIT 1
。
而分析器作的事情就是對你輸入的語句作 「詞法分析」 與 「語法分析」。
所謂 「詞法分析」 ,就是判斷每個你輸入的詞,好比分析器首先會判斷出你輸入的第一個詞是「SELECT」,第二個詞你輸入了「host」,等等。
而 「語法分析」 則是跟在 「詞法分析」 以後,就是依據你輸入的這些詞來判斷你輸入的是否符合語法規則。
假如符合語法規則,則會順利進行下去並返回相應信息。
在分析器工做結束後,若是語法有問題,那麼就會直接返回報錯信息,且不繼續向下運行。
若語法正確,那麼,則會到優化器部分的工做。優化器顧名思義,就是對該語句的執行作優化。
好比,在一個語句查詢某個表時,該表可能有多個索引,此時使用哪一個索引會使語句的執行效率最高?這就是優化器要作的事情。
再好比,執行語句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是沒法對運行時涉及到的表進行權限驗證的,好比使用了觸發器的狀況。所以在執行器這裏也要作一次執行時的權限驗證。
若是驗證成功,那麼則會使用該表對應的存儲引擎的接口,繼續執行語句。 最後將成功執行的結果返回給客戶端。
簡單來講,一條SQL語句在Mysql中執行,一共會經歷四步(算上鍊接Mysql),分別是鏈接、分析、優化與執行。每一步都會精確執行,若是發現有問題就會返回給客戶端相應的報錯。只有每一步都正確執行,最終纔會在客戶端獲得你想要查詢或操做的結果。