mysql中SQL執行過程詳解

 mysql執行一個查詢的過程,到底作了些什麼:mysql

 

  • 客戶端發送一條查詢給服務器;
  • 服務器先檢查查詢緩存,若是命中了緩存,則馬上返回存儲在緩存中的結果。不然進入下一階段。
  • 服務器段進行SQL解析、預處理,在優化器生成對應的執行計劃;
  • mysql根據優化器生成的執行計劃,調用存儲引擎的API來執行查詢。
  • 將結果返回給客戶端。

    實際上mysql執行的每一步都比較複雜,具體的過程以下sql

 第一步mysql客戶端和服務器通信

 

    1. 通信數據庫

    mysql客戶端和服務器之間的通信協議是「半雙工」的,這意味着,在任何一個時刻,要麼由服務器向客戶端發送數據,要麼由客戶端向服務器發送數據,這兩個動做不能同時發生。這種協議讓mysql通訊簡單快速,但也限制了mysql。一個明顯的限制是,這意味着沒辦法進行流量限制。一旦一端開始發生消息,另外一端要接收完整個消息才能響應他。緩存

    客戶端用一個單獨的數據包將查詢傳給服務器。一旦客戶端發送了請求,他能作的事情就只是等待結果了。服務器

    相反的,通常服務器響應給用戶的數據一般不少,由多個數據包組成。當服務器開始響應客戶端請求時,客戶端必須完整的接受整個返回結果,而不是簡單的只收取前面幾條結果,而後讓服務器中止發送數據。數據結構

    多數鏈接mysql的庫函數均可以得到所有結果並緩存到內存裏,還能夠逐行獲取所須要的數據。默認通常是得到所有結果並緩存到內存中。mysql一般須要等全部的數據都已經發送給客戶端才能釋放這條查詢所佔用的資源,因此接受所有結果並緩存一般能夠減小服務器的壓力,讓查詢可以早點結束、早點釋放對應的資源。架構

 2.應用程序把查詢SQL語句發送給服務器端執行tcp

在數據庫層執行SQL語句時,應用程序會鏈接到相應的數據庫服務器,把SQL語句發送給服務器處理。函數

 

第二步:查詢緩存

 

在解析一個查詢語句以前,若是查詢緩存(MySQL默認打開,可使用have_query_cache查看)是打開的,在接收到查詢請求後,mysql並不會直接去數據庫查詢,而是優先檢查這個查詢是否命中查詢緩存中的數據(某條給定的查詢語句在第一次執行時,服務器會緩存這條查詢語句和他返回的結果)。優化

而其中是否命中緩存是將此查詢語句和緩存中的查詢語句進行比對,若是徹底相同,那就認爲它們是相同的,就認爲命中緩存了(是經過一個對大小寫敏感的哈希查找實現的)。

若是當前的查詢剛好命中了查詢緩存,那麼在返回查詢結果以前mysql會檢查一次用戶權限。這仍然是無須解析查詢SQL語句的,由於在查詢緩存中已經存放了當前 查詢須要訪問的表信息。若是權限沒有問題,mysql會跳過全部其餘階段,直接從緩存中拿到結果並返回給客戶端。這種狀況下,查詢不會被解析,不用生成執行計劃,不會被執行。

若是當前的查詢沒有命中查詢緩存,這種狀況下查詢就會進入下一階段的處理。

 

第三步:查詢優化處理,生成執行計劃

 

接下來服務器會將一個SQL轉換成一個執行計劃,而這個階段包括:解析SQL預處理優化SQL執行計劃,其中任何一個階段出錯都會致使查詢進行不下去。而後mysql在依照這個執行計劃和存儲引擎進行交互。

 

  • 解析SQL:Mysql經過將SQL語句進行解析(語法解析器),並生成一棵對應的解析樹。MySQL解析器將使用MySQL語法規則驗證和解析查詢,如將驗證是否使用錯誤的關鍵字,或者關鍵字的順序是否正確。
  • 預處理:預處理器根據一些Mysql規則進一步檢查解析樹是否合法,如數據表和數據列是否存在,解析列名和別名,是否有歧義。接下來預處理器會驗證用戶權限。查看用戶是否有相應的操做權限。。
  • 優化SQL:當語法樹被認爲是合法的了,優化器將SQL語句轉化成執行計劃,一條查詢能夠有不少種執行方式,最後都返回相同的結果,最後找到其中最好的執行計劃(Mysql使用基於成本的優化器,它將嘗試預測一個查詢使用某種執行計劃的成本,選擇其中成本最小的一個)。

    

    優化器的做用就是找到這其中最好的執行計劃。

 

第四步:查詢執行引擎

 

 在解析和優化階段,mysql將生成查詢對應的執行計劃,mysql的查詢執行引擎則根據這個執行計劃來完成整個查詢。這裏執行計劃是一個數據結構,而不是和不少其餘的關係型數據庫那樣對應的字節碼。

 mysql簡單的根據執行計劃給出的指令逐步執行。在根據執行計劃逐步執行的過程當中,有大量的操做須要經過調用存儲引擎實現的接口來完成,這些接口即爲「handler API」接口。爲了執行查詢,mysql只須要重複執行計劃中的各個操做,直到完成全部的數據查詢。查詢中的每個表由一個handler的實例表示。(實際上,在優化階段Mysql就爲每個表建立了一個handelr實例,優化器能夠根據這些實例的接口獲取表的相關信息,如表的全部列名、索引統計信息等)

 

第五步:將查詢結果返回客戶端

 

查詢執行的最後一個階段是將結果返回給客戶端。即便查詢不須要返回結果給客戶端,mysql仍然會返回這個查詢的一些信息,如該查詢影響到的行數。

若是查詢能夠被緩存,那麼mysql在這個階段也會將結果放到查詢緩存中。

mysql將結果集返回客戶端是一個增量、逐步返回的過程。這樣有兩個好處:服務器端無須存儲太多的結果,也就不會由於返回太多結果而消耗太多的內存;這樣處理也讓msyql客戶端第一時間得到返回的結果。

結果集中的每一行都會以一個知足mysql客戶端/服務器通訊協議的包發送,再經過tcp協議進行傳輸,在tcp傳輸的過程當中,可能對mysql的封包進行緩存而後批量傳輸。

 

-------------------------------------------

解析:

致使Mysql優化器選擇錯誤的執行計劃的緣由:

 

  • Mysql的最優可能和你想的最優不同。你可能但願執行時間最短,但Mysql根據其成本計算得出的最優計劃,可能執行時間並非最短的。
  • 優化器有時候可能會沒法估算全部的可能的執行計劃,致使有可能錯誤實際上最優的執行計劃。
  • 執行計劃中成本估算不等同於實際執行的成本。若有時候執行計劃須要讀取更多的頁面,但它成本卻更小。Mysql層面沒法知道哪些頁面在內存中,哪些在磁盤上,因此實際執行過程當中須要多少次物理I/O沒法得知。
  • Mysql不會考慮不受其控制的操做的成本,如執行用戶自定義的函數的成本。
  • 統計信息不許確:Mysql依賴存儲引擎提供的統計信息(每一個表有多少個頁面、數據行和索引的長度、索引的分佈等)來估計成本,有的存儲引擎提供的信息誤差可能比較大。如InnoDB由於MVCC的架構,並不能維護一個數據表的行數的精確統計信息。

 

查詢結果/語句不會被緩存的狀況

  • 若是表上有任何鎖,對這個表的任何查詢語句都是沒法被緩存的。
  • 查詢語句中有一些不肯定的數據。如now()。
  • 有用戶自定義函數、用戶變量不會被緩存。
  • 包含任何不肯定函數的語句。
  • 當查詢的結果大於緩存大小時,結果不會被緩存

 

Mysql可以處理的優化類型(能夠作出的優化措施)

  • 從新定義關聯表的順序。數據表的關聯並非總按照查詢中指定的順序進行。
  • 使用等價轉換規則。如移除一些恆成立或恆不成立的判斷。
  • 可能的表達式轉換爲常熟表達式
  • 提早終止查詢。如使用limit。

執行計劃


Mysql並不會生成查詢字節碼來執行查詢。Mysql生成查詢的一棵指令樹,而後經過存儲引擎執行完成這棵指令樹並返回結果。Mysql關聯執行的策略很簡單:Mysql對任何關聯都執行嵌套循環關聯操做,即Mysql先在一個表中循環取出單條數據,而後再嵌套到下一個表中尋找匹配的行,依次下去,直到找到全部表中匹配的行爲止。而後根據各個表匹配的行,返回查詢中須要各個列。Mysql會嘗試在最後一個關聯表中找到全部匹配的行,若是最後一個關聯表沒法找到更多的行之後,Mysql返回到上一層此關聯表,看可否找到更多的匹配記錄,依次類推迭代執行。因此Mysql的執行計劃老是一顆左側深度優先的樹。

相關文章
相關標籤/搜索