mysql執行一個查詢的過程,到底作了些什麼:mysql
實際上mysql執行的每一步都比較複雜,具體的過程以下sql
1. 通信數據庫
mysql客戶端和服務器之間的通信協議是「半雙工」的,這意味着,在任何一個時刻,要麼由服務器向客戶端發送數據,要麼由客戶端向服務器發送數據,這兩個動做不能同時發生。這種協議讓mysql通訊簡單快速,但也限制了mysql。一個明顯的限制是,這意味着沒辦法進行流量限制。一旦一端開始發生消息,另外一端要接收完整個消息才能響應他。緩存
客戶端用一個單獨的數據包將查詢傳給服務器。一旦客戶端發送了請求,他能作的事情就只是等待結果了。服務器
相反的,通常服務器響應給用戶的數據一般不少,由多個數據包組成。當服務器開始響應客戶端請求時,客戶端必須完整的接受整個返回結果,而不是簡單的只收取前面幾條結果,而後讓服務器中止發送數據。數據結構
多數鏈接mysql的庫函數均可以得到所有結果並緩存到內存裏,還能夠逐行獲取所須要的數據。默認通常是得到所有結果並緩存到內存中。mysql一般須要等全部的數據都已經發送給客戶端才能釋放這條查詢所佔用的資源,因此接受所有結果並緩存一般能夠減小服務器的壓力,讓查詢可以早點結束、早點釋放對應的資源。架構
2.應用程序把查詢SQL語句發送給服務器端執行tcp
在數據庫層執行SQL語句時,應用程序會鏈接到相應的數據庫服務器,把SQL語句發送給服務器處理。函數
在解析一個查詢語句以前,若是查詢緩存(MySQL默認打開,可使用have_query_cache查看)是打開的,在接收到查詢請求後,mysql並不會直接去數據庫查詢,而是優先檢查這個查詢是否命中查詢緩存中的數據(某條給定的查詢語句在第一次執行時,服務器會緩存這條查詢語句和他返回的結果)。優化
而其中是否命中緩存是將此查詢語句和緩存中的查詢語句進行比對,若是徹底相同,那就認爲它們是相同的,就認爲命中緩存了(是經過一個對大小寫敏感的哈希查找實現的)。
若是當前的查詢剛好命中了查詢緩存,那麼在返回查詢結果以前mysql會檢查一次用戶權限。這仍然是無須解析查詢SQL語句的,由於在查詢緩存中已經存放了當前 查詢須要訪問的表信息。若是權限沒有問題,mysql會跳過全部其餘階段,直接從緩存中拿到結果並返回給客戶端。這種狀況下,查詢不會被解析,不用生成執行計劃,不會被執行。
若是當前的查詢沒有命中查詢緩存,這種狀況下查詢就會進入下一階段的處理。
接下來服務器會將一個SQL轉換成一個執行計劃,而這個階段包括:解析SQL、預處理、優化SQL執行計劃,其中任何一個階段出錯都會致使查詢進行不下去。而後mysql在依照這個執行計劃和存儲引擎進行交互。
優化器的做用就是找到這其中最好的執行計劃。
在解析和優化階段,mysql將生成查詢對應的執行計劃,mysql的查詢執行引擎則根據這個執行計劃來完成整個查詢。這裏執行計劃是一個數據結構,而不是和不少其餘的關係型數據庫那樣對應的字節碼。
mysql簡單的根據執行計劃給出的指令逐步執行。在根據執行計劃逐步執行的過程當中,有大量的操做須要經過調用存儲引擎實現的接口來完成,這些接口即爲「handler API」接口。爲了執行查詢,mysql只須要重複執行計劃中的各個操做,直到完成全部的數據查詢。查詢中的每個表由一個handler的實例表示。(實際上,在優化階段Mysql就爲每個表建立了一個handelr實例,優化器能夠根據這些實例的接口獲取表的相關信息,如表的全部列名、索引統計信息等)
查詢執行的最後一個階段是將結果返回給客戶端。即便查詢不須要返回結果給客戶端,mysql仍然會返回這個查詢的一些信息,如該查詢影響到的行數。
若是查詢能夠被緩存,那麼mysql在這個階段也會將結果放到查詢緩存中。
mysql將結果集返回客戶端是一個增量、逐步返回的過程。這樣有兩個好處:服務器端無須存儲太多的結果,也就不會由於返回太多結果而消耗太多的內存;這樣處理也讓msyql客戶端第一時間得到返回的結果。
結果集中的每一行都會以一個知足mysql客戶端/服務器通訊協議的包發送,再經過tcp協議進行傳輸,在tcp傳輸的過程當中,可能對mysql的封包進行緩存而後批量傳輸。
-------------------------------------------
解析:
致使Mysql優化器選擇錯誤的執行計劃的緣由:
查詢結果/語句不會被緩存的狀況
Mysql可以處理的優化類型(能夠作出的優化措施)
執行計劃
Mysql並不會生成查詢字節碼來執行查詢。Mysql生成查詢的一棵指令樹,而後經過存儲引擎執行完成這棵指令樹並返回結果。Mysql關聯執行的策略很簡單:Mysql對任何關聯都執行嵌套循環關聯操做,即Mysql先在一個表中循環取出單條數據,而後再嵌套到下一個表中尋找匹配的行,依次下去,直到找到全部表中匹配的行爲止。而後根據各個表匹配的行,返回查詢中須要各個列。Mysql會嘗試在最後一個關聯表中找到全部匹配的行,若是最後一個關聯表沒法找到更多的行之後,Mysql返回到上一層此關聯表,看可否找到更多的匹配記錄,依次類推迭代執行。因此Mysql的執行計劃老是一顆左側深度優先的樹。