MySQL探秘 SQL語句執行過程詳解

2021-09-13 02:39:12 字數 2100 閱讀 3333

當希望mysql能夠以更高的效能執行查詢時,最好的辦法就是弄清楚mysql是如何優化和執行查詢的。一旦理解了這一點,很多查詢優化工作實際上就是遵循一些原則能夠按照預想的合理的方式執行。

如下圖所示,當向mysql傳送乙個請求的時候,mysql到底做了什麼:

客戶端傳送一條查詢給伺服器。

伺服器先檢查查詢快取,如果命中了快取,則立刻返回儲存在快取中的結果。否則進入下一階段。

伺服器端進行sql解析、預處理,再由優化器生成對應的執行計畫。

mysql根據優化器生成的執行計畫,再呼叫儲存引擎的api來執行查詢。

將結果返回給客戶端。

查詢快取

需要注意的是,mysql 8.0 版本直接將查詢快取的整塊功能刪掉了,也就是說 8.0 開始徹底沒有這個功能了。

mysql查詢快取儲存查詢返回的完整結構。當查詢命中該快取時,mysql會立刻返回結果,跳過了解析、優化和執行階段。

查詢快取系統會跟蹤查詢中涉及的每個表,如果這些表發生了變化,那麼和這個表相關的所有快取資料都將失效。

mysql將快取存放在乙個引用表中,通過乙個雜湊值引用,這個雜湊值包括了以下因素,即查詢本身、當前要查詢的資料庫、客戶端協議的版本等一些其他可能影響返回結果的資訊。

當判斷快取是否命中時,mysql不會進行解析查詢語句,而是直接使用sql語句和客戶端傳送過來的其他原始資訊。所以,任何字元上的不同,例如空格、註解等都會導致快取的不命中。

當查詢語句中有一些不確定的資料時,則不會被快取。例如包含函式now()或者current_date()的查詢不會快取。包含任何使用者自定義函式,儲存函式,使用者變數,臨時表,mysql資料庫中的系統表或者包含任何列級別許可權的表,都不會被快取。

有一點需要注意,mysql並不是會因為查詢中包含乙個不確定的函式而不檢查查詢快取,因為檢查查詢快取之前,mysql不會解析查詢語句,所以也無法知道語句中是否有不確定的函式。

事實則是,如果查詢語句中包含任何的不確定的函式,那麼其查詢結果不會被快取,因為查詢快取中也無法找到對應的快取結果。

有關查詢快取的配置如下所示。

對查詢快取的優化是資料庫效能優化的重要一環。判斷流程大致如下圖所示。

快取命中率可以通過如下公式計算:qcache_hits/(qcache_hits + com_select)來計算。

解析和預處理

解析器通過關鍵字將sql語句進行解析,並生成對應的解析樹。mysql解析器將使用mysql語法規則驗證和解析查詢。

預處理器則根據一些mysql規則進行進一步檢查解析書是否合法,例如檢查資料表和資料列是否存在,還會解析名字和別名,看看它們是否有歧義。

查詢優化器

查詢優化器會將解析樹轉化成執行計畫。一條查詢可以有多種執行方法,最後都是返回相同結果。優化器的作用就是找到這其中最好的執行計畫。

生成執行計畫的過程會消耗較多的時間,特別是存在許多可選的執行計畫時。如果在一條sql語句執行的過程中將該語句對應的最終執行計畫進行快取,當相似的語句再次被輸入伺服器時,就可以直接使用已快取的執行計畫,從而跳過sql語句生成執行計畫的整個過程,進而可以提高語句的執行速度。

mysql使用基於成本的查詢優化器(cost-based optimizer,cbo)。它會嘗試**乙個查詢使用某種執行計畫時的成本,並選擇其中成本最少的乙個。

優化器會根據優化規則對關係表示式進行轉換,這裡的轉換是說乙個關係表示式經過優化規則後會生成另外乙個關係表示式,同時原有表示式也會保留,經過一系列轉換後會生成多個執行計畫,然後cbo會根據統計資訊和代價模型(cost model)計算每個執行計畫的cost,從中挑選cost最小的執行計畫。由上可知,cbo中有兩個依賴:統計資訊和代價模型。統計資訊的準確與否、代價模型的合理與否都會影響cbo選擇最優計畫。

有關優化器的原理十分複雜,這裡就不進行詳細講解了,大家可以自行學習。

查詢執行引擎

在解析和優化階段,mysql將生成查詢對應的執行計畫,mysql的查詢執行引擎根據這個執行計畫來完成整個查詢。這裡執行計畫是乙個資料結構,而不是和其他的關係型資料庫那樣生成對應的位元組碼。

返回結果給客戶端

如果查詢可以被快取,那麼mysql在這個階段頁會將結果存放到查詢快取中。

mysql將結果集返回給客戶端是乙個增量、逐步返回的過程。在查詢生成第一條結果時,mysql就可以開始向客戶端逐步返回結果集了。

檢視MYSQL已經執行過的sql語句

編輯 etc my.cnf檔案,在 mysqld 節下面新增 log tmp sql row.log行 或者其他路徑,有時因為檔案許可權問題,可能記錄不下來 修改完畢後,記得重啟 mysql service mysql restart 或者 etc init.d mysqld stop etc in...

MySQL監控全部執行過的sql語句

檢視是否開啟日誌記錄 show variables like general log variable name value general log off general log file data0 logs mysql general.log off 關閉 on 開啟 臨時開啟日誌記錄 set...

MySQL監控全部執行過的sql語句

先登入mysql 檢視是否開啟日誌記錄 off 關閉 on 開啟 臨時開啟日誌記錄 set global general log on 這時執行的所有sql都會被記錄下來,但是如果重啟mysql就會停止記錄需要重新設定 mysql exit檢視100行日誌 tail 100f data mysql ...