執行流程
如下圖所示,我們可以看到當向 MySQL 發送一個請求時,MySQL 到底做了什么:

- 客戶端發送一條査詢給服務器。
- 服務器先檢查査詢緩存,如果命中了緩存,則立刻返回存儲在緩存中的結果。否則進入下一階段。
- 服務器端進行 SQL 解析、預處理,再由優化器生成對應的執行計划。
- MySQL 根據優化器生成的執行計划,調用存儲引擎的 API 來執行查詢。
- 將結果返回給客戶端。
查詢緩存
在解析一個查詢語句之前,如果查詢緩存時打開的,那么 MySQL 會優先檢查這個查詢是否命中查詢緩存中的數據。這個檢查時通過一個對大小寫敏感的哈希查找實現的。查詢和緩存中的查詢即使只有一個字節不同,那也不會匹配緩存結果。
如果當前的查詢恰好命中了緩存,那么在返回結果之前 MySQL 會檢查一次用戶權限。這仍然是無須解析查詢 SQL 語句的,因為在查詢緩存中已經存放了當前查詢需要訪問的表信息。如果權限沒有問題,MySQL 會跳過所有其他階段,直接從緩存中拿到結果並返回給客戶端。跳過了解析、優化和執行階段。
查詢緩存系統會跟蹤查詢表中涉及的每個表,如果這些表發生變化,那么和這個表相關的所有緩存數據都將失效。這種機制效率看起來比較低,因為數據變化時很有可能對應的查詢結果並沒有變更,但是這種簡單實現代價很小,而這點對於一個非常繁忙的系統來說非常重要。
有關查詢緩存的配置
query_cache_type
是否打開查詢緩存。可以設置成 OFF、ON 或者 DEMAND。DEMAND 表示只有在查詢語句中明確寫明 SQL_CACHE 的語句才放入查詢緩存。
query_cache_size
查詢緩存使用的總內存空間,單位是字節。這個值必須是 1024 的整數倍,否則 MySQL實際分配的數據會和你指定的略有不同。
query_cache_min_res_unit
在查詢緩存中分配內存塊時的最小單位。
query_cache_limit
MySQL 能夠緩存的最大查詢結果。如果查詢結果大於這個值,則不會被緩存。
query_cache_wlock_invalidate
如果某個數據表被其他的連接鎖住,是否仍然從拆線呢緩存中返回結果。這個參數默認是 OFF,這可能在一定程度上會改變服務器的行為,因為這使得數據庫可能返回其他線程鎖住的數據。將參數設置為 ON,則不會從緩存中讀取這類數據,但是這可能會增加鎖等待。對於絕大多數應用來說無需注意這個細節,所以默認設置通常是沒有問題的。
語法解析器和預處理
首先,MySQL 通過關鍵字將 SQL 語句進行解析,並生成一顆對應的“解析樹”。MySQL 解析器將使用 MySQL 語法規則驗證和解析查詢。例如,它將驗證是否使用錯誤的關鍵字,或者使用關鍵字的順序是否正確等,再或者它還會驗證引號是否能前后正確匹配。
預處理器則根據一些 MySQL 規則進一步檢查解析樹是否合法,例如,這里將檢查數據表和數據列是否存在,還會解析名字和別名,看看它們是否有歧義。
下一步預處理器會驗證權限。這通常很快,除非服務器上有非常多的權限配置。
查詢優化器
現在語法樹被認為是合法的了,並且由優化器將其轉化成執行計划。一條查詢可以有很多種執行方式,最后都返回相同的結果。優化器的作用就是找到這其中最好的執行計划。
MySQL 使用基於成本的優化器,它將嘗試預測一個查詢使用某種執行計划時的成本,並選擇其中成本最小的一個。
MySQL 查詢優化器在生成查詢的執行計划時,需要向存儲引擎獲取相應的統計信息。存儲引擎則提供給優化器對應的統計信息,包括:每個表或索引有多少個頁面、每個表的每個索引的基數是多少、數據行和索引長度、索引的分布信息等。優化器根據這些信息來選擇一個最優的執行計划。
查詢執行引擎
相對於查詢優化階段,查詢執行階段不是那么復雜:MySQL 只是簡單地根據執行計划給出地指令逐步執行。在根據計划逐步執行的過程中,有大量的操作需要通過調用存儲引擎實現的接口來完成。
返回結果給客戶端
查詢執行的最后一個階段是將結果返回給客戶端。即使查詢不需要返回結果集給客戶端,MySQL 仍然會返回這個查詢的一些信息,如該查詢影響到的行數。
如果查詢可以被緩存,那么 MySQL 在這個階段也會將結果存放到查詢緩存中。