mysql查詢執行路徑
1. 客戶端傳送一條查詢給伺服器;
2. 伺服器先會檢查查詢快取,如果命中了快取,則立即返回儲存在快取中的結果。否則進入下一階段;
3. 伺服器端進行sql解析、預處理,再由優化器生成對應的執行計畫;
4. mysql根據優化器生成的執行計畫,呼叫儲存引擎的api來執行查詢;
5. 將結果返回給客戶端。
查詢快取(query cache)
在解析乙個查詢語句之前,如果查詢快取是開啟的,那麼mysql會優先檢查這個查詢是否命中查詢快取中的資料。這個檢查是通過乙個對大小寫敏感的雜湊查詢實現的。查詢和快取中的查詢即使只有乙個位元組不同,那也不會匹配快取結果,這種情況查詢會進入下乙個階段的處理。
如果當前的查詢恰好命中了查詢快取,那麼在返回查詢結果之前mysql會檢查一次使用者許可權。這仍然是無須解析查詢sql語句的,因為在查詢快取中已經存放了當前查詢需要訪問的表資訊。如果許可權沒有問題,mysql會跳過所有其他階段,直接從快取中拿到結果並返回給客戶端。這種情況下,查詢不會被解析,不用生成執行計畫,不會被執行。
快取配置引數:
query_cache_limit: mysql能夠快取的最大結果,如果超出,則增加 qcache_not_cached的值,並刪除查詢結果
query_cache_min_res_unit: 分配記憶體塊時的最小單位大小
query_cache_size: 快取使用的總記憶體空間大小,單位是位元組,這個值必須是1024的整數倍,否則mysql實際分配可能跟這個數值不同(感覺這個應該跟檔案系統的blcok大小有關)
query_cache_type: 是否開啟快取off: 關閉on: 總是開啟
query_cache_wlock_invalidate: 如果某個資料表被鎖住,是否仍然從快取中返回資料,預設是off,表示仍然可以返回
語法解析器和預處理器
首先,mysql通過關鍵字將sql語句進行解析,並生成一棵對應的「解析樹」。mysql解析器將使用mysql語法規則驗證和解析查詢。例如,它將驗證是否使用錯誤的關鍵字,或者使用關鍵字的順序是否正確等,再或者它還會驗證引號是否能前後正確的匹配。
預處理器則根據一些mysql規則進一步檢查解析樹是否合法,例如,這裡講檢查資料表和資料列是否存在,還會解析名字和別名,看看它們是否有歧義。
下一步預處理器會驗證許可權,這通常很快,除非伺服器上有非常多的許可權設定。
查詢優化器
現在語法樹被認為合法的了,並且由優化器將其轉化為執行計畫。一條查詢可以由很多種執行方式,最後都返回相同的結果。優化器的作用就是找到這其中最好的執行計畫。
mysql使用基於成本的優化器,它將嘗試**乙個查詢使用某種執行計畫的成本,並選擇其中成本最小的乙個。最初,成本的最小單位是隨機讀取乙個4k資料頁的成本,後來成本計算公式變得更加複雜,並且引入了一些「因子」來估算某些操作的代價,如當執行一次where條件比較的成本。可以通過查詢當前會話的last_query_cost的值來得知mysql計算的當前查詢的成本。
有很多種原因會導致mysql優化器選擇錯誤的執行計畫,比如:
1. 統計資訊不準確。
2. 執行計畫中的成本估算不等同於實際的執行計畫的成本。
3. mysql的最優可能與你想的最優不一樣。
4. mysql從不考慮其他併發的查詢,這可能會影響當前查詢的速度。
5. mysql也不是任何時候都是基於成本的優化,有時候也會基於一些固定的規則。
6. mysql不會考慮不受其控制的成本,例如執行儲存過程或者使用者自定義的函式的成本。
mysql的查詢優化使用了很多優化策略來生成乙個最優的執行的計畫。優化策略可以分為兩種,靜態優化和動態優化。靜態優化可以直接對解析樹進行分析,並完成優化。例如優化器可以通過一些簡單的代數變換將where條件轉換成另一種等價形式。靜態優化不依賴於特別的數值,如where條件中帶入的一些常數等。靜態優化在第一次完成後就一直有效,即使使用不同的引數重複查詢也不會變化,可以認為是一種「編譯時優化」。
相反,動態優化則和查詢的上下文有關。也可能和很多其他因素有關,例如where條件中的取值、索引中條目對應的資料行數等,這些需要每次查詢的時候重新評估,可以認為是「執行時優化」。
下面是一些mysql能夠處理的優化型別:
1. 重新定義關聯表的順序
資料表的關聯並不總是按照在查詢中指定的順序進行,決定關聯的順序是優化器很重要的一部分功能。
2. 將外連線轉化成內連線
並不是所有的outer join語句都必須以外連線的方式執行。諸多因素,例如where條件、庫表結構都可能會讓外連線等價於乙個內連線。mysql能夠識別這點並重寫查詢,讓其可以調整關聯順序。
3. 使用等價變換規則
mysql可以使用一些等價變換來簡化並規範表示式。它可以合併和減少一些比較,還可以移除一些恆成立和一些恆不成立的判斷。例如:(5=5 and a>5)將被改寫為a>5。類似的,如果有(a5 and b=c and a=5。
4. 優化count()、min()和max()
索引和列是否為空通常可以幫助mysql優化這類表示式。例如,要找到一列的最小值,只需要查詢對應b-tree索引最左端的記錄,mysql可以直接獲取索引的第一行記錄。在優化器生成執行計畫的時候就可以利用這一點,在b-tree索引中,優化器會講這個表示式最為乙個常數對待。類似的,如果要查詢乙個最大值,也只需要讀取b-tree索引的最後乙個記錄。如果mysql使用了這種型別的優化,那麼在explain中就可以看到「select tables optimized away」。從字面意思可以看出,它表示優化器已經從執行計畫中移除了該錶,並以乙個常數取而代之。
類似的,沒有任何where條件的count(*)查詢通常也可以使用儲存引擎提供的一些優化,例如,myisam維護了乙個變數來存放資料表的行數。
5. 預估並轉化為常數表示式
6. 覆蓋索引掃瞄
當索引中的列包含所有查詢中需要使用的列的時候,mysql就可以使用索引返回需要的資料,而無需查詢對應的資料行。
7. 子查詢優化
mysql在某些情況下可以將子查詢轉換成一種效率更高的形式,從而減少多個查詢多次對資料進行訪問。
8. 提前終止查詢
在發現已經滿足查詢需求的時候,mysql總是能夠立即終止查詢。乙個典型的例子就是當使用了limit子句的時候。除此之外,mysql還有幾種情況也會提前終止查詢,例如發現了乙個不成立的條件,這時mysql可以立即返回乙個空結果。
上面的例子可以看出,查詢在優化階段就已經終止。
9. 等值傳播
10. 列表in()的比較
在很多資料庫系統中,in()完全等同於多個or條件的字句,因為這兩者是完全等價的。在mysql中這點是不成立的,mysql將in()列表中的資料先進行排序,然後通過二分查詢的方式來確定列表中的值是否滿足條件,這是乙個o(log n)複雜度的操作,等價轉換成or的查詢的複雜度為o(n),對於in()列表中有大量取值的時候,mysql的處理速度會更快。
查詢執行引擎
在解析和優化階段,mysql將生成查詢對應的執行計畫,mysql的查詢執行引擎則根據這個執行計畫來完成整個查詢。這裡執行計畫是乙個資料結構,而不是和很多其他的關係型資料庫那樣會生成對應的位元組碼。
相對於查詢優化階段,查詢執行階段不是那麼複雜:mysql只是簡單的根據執行計畫給出的指令逐步執行。在根據執行計畫逐步執行的過程中,有大量的操作需要通過呼叫儲存引擎實現的介面來完成,這些介面就是我們稱為「handler api」的介面。實際上,mysql在優化階段就為每個表建立了乙個handler例項,優化器根據這些例項的介面可以獲取表的相關資訊,包括表的所有列名、索引統計資訊等。
返回結果給客戶端
查詢執行的最後乙個階段是將結果返回給客戶端。即使查詢不需要返回結果給客戶端,mysql仍然會返回這個查詢的一些資訊,如查詢影響到的行數。
如果查詢可以被快取,那麼mysql在這個階段,會將結果存放到查詢快取中。
mysql將結果返回客戶端是乙個增量、逐步返回的過程。例如,在關聯表操作時,一旦伺服器處理完最後乙個關聯表,開始生成第一條結果時,mysql就可以開始向客戶端逐步返回結果集了。
這樣處理有兩個好處:伺服器無需儲存太多的結果,也就不會因為要返回太多的結果而消耗太多的記憶體。另外,這樣的處理也讓mysql客戶端第一時間獲得返回的結果。
結果集中的每一行都會以乙個滿足mysql客戶端/伺服器通訊協議的封包傳送,再通過tcp協議進行傳輸,在tcp傳輸過程中,可能對mysql的封包進行快取然後批量傳輸。
mysql查詢過程(一)
mysql查詢過程 客戶端 服務端通訊協議 mysql客戶端 服務端通訊協議是 半雙工 的 在任一時刻,要麼是伺服器向客戶端傳送資料,要麼是客戶端向伺服器傳送資料,這兩個動作不能同時發生。一旦一端開始傳送訊息,另一端要接收完整個訊息才能響應它,所以我們無法也無須將乙個訊息切成小塊獨立傳送,也沒有辦法...
mysql多表連線查詢過程 mysql多表連線查詢
二 內連線 join 或 inner join sql語句 select from student inner join course on student.id course.id 執行結果 inner join 是比較運算子,只返回符合條件的行。此時相當於 select from student...
Elasticsearch查詢過程
客戶端向集群中的某個節點 假設節點1 發起查詢請求,節點1會建立乙個from size大小的佇列 from 偏移量,size 要取回的文件個數 節點1向集群中所有其他的分片 主或從 發起查詢請求,每個分片也會建立乙個from size大小的佇列,並將查詢結果新增到佇列中。其他分片將查詢到的文件id和...