- 客戶端發送一條查詢給服務器;
- 服務器先檢查查詢緩存,如果命中了緩存,則立刻返回存儲在緩存中的結果。否則進入下一階段。
- 服務器段進行SQL解析、預處理,在優化器生成對應的執行計划;
- mysql根據優化器生成的執行計划,調用存儲引擎的API來執行查詢。
- 將結果返回給客戶端。
實際上mysql執行的每一步都比較復雜,具體的過程如下:
1、mysql客戶端和服務器通訊
mysql客戶端和服務器之間的通訊協議是“半雙工”的,這意味着,在任何一個時刻,要么由服務器向客戶端發送數據,要么由客戶端向服務器發送數據,這兩個動作不能同時發生。這種協議讓mysql通信簡單快速,但也限制了mysql。一個明顯的限制是,這意味着沒辦法進行流量限制。一旦一端開始發生消息,另一端要接收完整個消息才能響應他。
客戶端用一個單獨的數據包將查詢傳給服務器。一旦客戶端發送了請求,他能做的事情就只是等待結果了。
相反的,一般服務器響應給用戶的數據通常很多,由多個數據包組成。當服務器開始響應客戶端請求時,客戶端必須完整的接受整個返回結果,而不是簡單的只收取前面幾條結果,然后讓服務器停止發送數據。
多數連接mysql的庫函數都可以獲得全部結果並緩存到內存里,還可以逐行獲取所需要的數據。默認一般是獲得全部結果並緩存到內存中。mysql通常需要等所有的數據都已經發送給客戶端才能釋放這條查詢所占用的資源,所以接受全部結果並緩存通常可以減少服務器的壓力,讓查詢能夠早點結束、早點釋放對應的資源。
2、查詢狀態
對於mysql連接,任何時刻都有一個狀態,該狀態表示了mysql當前正在做什么。使用show full processlist命令查看當前狀態。在一個查詢生命周期中,狀態會變化很多次,下面是這些狀態的解釋:
- sleep:線程正在等待客戶端發送新的請求;
- query:線程正在執行查詢或者正在將結果發送給客戶端;
- locked:在mysql服務器層,該線程正在等待表鎖。在存儲引擎級別實現的鎖,例如InnoDB的行鎖,並不會體現在線程狀態中。對於MyISAM來說這是一個比較典型的狀態。
- analyzing and statistics:線程正在收集存儲引擎的統計信息,並生成查詢的執行計划;
- copying to tmp table:線程在執行查詢,並且將其結果集復制到一個臨時表中,這種狀態一般要么是做group by操作,要么是文件排序操作,或者union操作。如果這個狀態后面還有on disk標記,那表示mysql正在將一個內存臨時表放到磁盤上。
- sorting Result:線程正在對結果集進行排序。
- sending data:線程可能在多個狀態間傳送數據,或者在生成結果集,或者在想客戶端返回數據。
3、查詢緩存
在解析一個查詢語句之前,如果查詢緩存是打開的,那么mysql會優先檢查這個查詢是否命中查詢緩存中的數據。這個檢查是通過一個對大小寫敏感的哈希查找實現的。查詢和緩存中的查詢即使只有一個字節不同,那也不會匹配緩存結果,這種情況下查詢就會進入下一階段的處理。
如果當前的查詢恰好命中了查詢緩存,那么在返回查詢結果之前mysql會檢查一次用戶權限。這仍然是無須解析查詢SQL語句的,因為在查詢緩存中已經存放了當前 查詢需要訪問的表信息。如果權限沒有問題,mysql會跳過所有其他階段,直接從緩存中拿到結果並返回給客戶端。這種情況下,查詢不會被解析,不用生成執行計划,不會被執行。
4、查詢優化處理
查詢的生命周期的下一步是將一個SQL轉換成一個執行計划,mysql在依照這個執行計划和存儲引擎進行交互。這包含多個子階段:解析SQL、預處理、優化SQL執行計划。這個過程中任何錯誤都可能終止查詢。
- 語法解析器和預處理:首先mysql通過關鍵字將SQL語句進行解析,並生成一顆對應的“解析樹”。mysql解析器將使用mysql語法規則驗證和解析查詢;預處理器則根據一些mysql規則進一步檢查解析數是否合法。
- 查詢優化器:當語法樹被認為是合法的了,並且由優化器將其轉化成執行計划。一條查詢可以有很多種執行方式,最后都返回相同的結果。優化器的作用就是找到這其中最好的執行計划。
- 執行計划:mysql不會生成查詢字節碼來執行查詢,mysql生成查詢的一棵指令樹,然后通過存儲引擎執行完成這棵指令樹並返回結果。最終的執行計划包含了重構查詢的全部信息。
5、查詢執行引擎
在解析和優化階段,mysql將生成查詢對應的執行計划,mysql的查詢執行引擎則根據這個執行計划來完成整個查詢。這里執行計划是一個數據結構,而不是和很多其他的關系型數據庫那樣對應的字節碼。
mysql簡單的根據執行計划給出的指令逐步執行。在根據執行計划逐步執行的過程中,有大量的操作需要通過調用存儲引擎實現的接口來完成。為了執行查詢,mysql只需要重復執行計划中的各個操作,知道完成所有的數據查詢。
6、返回結果給客戶端
查詢執行的最后一個階段是將結果返回給客戶端。即使查詢不需要返回結果給客戶端,mysql仍然會返回這個查詢的一些信息,如該查詢影響到的行數。如果查詢可以被緩存,那么mysql在這個階段也會將結果放到查詢緩存中。
mysql將結果集返回客戶端是一個增量、逐步返回的過程。這樣有兩個好處:服務器端無須存儲太多的結果,也就不會因為返回太多結果而消耗太多的內存;這樣處理也讓msyql客戶端第一時間獲得返回的結果。
結果集中的每一行都會以一個滿足mysql客戶端/服務器通信協議的包發送,再通過tcp協議進行傳輸,在tcp傳輸的過程中,可能對mysql的封包進行緩存然后批量傳輸。