查詢的生命週期的下一步是將乙個sql轉換成乙個可執行計畫,mysql再按照這個計畫和儲存引擎進行互動預處理器則會根據一些mysql規則進一步檢查解析樹是否合法。它會檢查資料表和資料列是否存在,還會解析名字和別名,看看它們是否存在歧義。
當語法樹被認為是合法的時候,將轉由優化器去轉化成執行計畫。一條查詢可以有很多種執行方式,最後都返回相同的結果。優化器的作用就是找到這其中最好的執行計畫。
mysql使用的是基於成本的優化器,它將會嘗試**乙個查詢使用某種執行計畫時的成本,並選擇其中成本最小的那乙個。可以通過查詢當前會話的「last_query_cost」的值來的值mysql計算的當前查詢的成本。
這個結果表示mysql的優化器認為大概需要做1040個資料頁的隨機查詢才能夠完成上面的查詢。這是根據一系列的統計資訊計算的來的。優化器在評估成本時並不會考慮任何層面的快取,它假設讀取任何資料都需要一次磁碟i/o。
有很多種情況會導致mysql優化器選擇錯誤的執行計畫,如下所示:
mysql的查詢優化器是乙個非常複雜的不見,它使用了很多優化策略來生成乙個最優的執行計畫。優化策略可以簡單的分為兩種,一種是靜態優化,一種是動態優化。
靜態優化可以直接對解析樹進行分析,並完成優化。例如通過一些簡單的袋鼠變換將where條件轉換成另一種等價形式,可以認為是一種「編譯時優化」。
動態優化則是和查詢的上下文相關,也可能和很多其他因素有關,這些需要在每次查詢時重新評估,可以認為是「執行時優化」
。在執行語句和儲存過程的時候,動態優化和靜態優化的區別很重要。mysql對查詢的靜態優化只需要做一次,但是對查詢的動態優化則在每次執行時都需要重新評估。有時候甚至在查詢的執行過程中也會重新優化。
下面是一些mysql可以處理的優化型別:
重新定義關聯表的順序
將外連線轉化為內連線
使用等價變換規則。它可以合併和減少一些比較,還可以移除一些恆成立和一些恆不成立的判斷。
優化count()、min()和max()。索引和列是否為空通常可以幫助mysql優化這類表示式。比如需要找到某一列的最小值,只需要查詢對應b-tree索引的最左端記錄即可。
預估並轉化為常量表示式。當mysql檢測到乙個表示式可以轉化為常數時,就會一直把該表示式作為常數進行優化處理。
覆蓋索引掃瞄。 當索引中的列包含所有查詢中需要使用的列的時候,mysql就可以使用索引返回需要的資料,而無需查詢對應的資料行。
子查詢優化
提前終止查詢。當發現已經滿足查詢需求的時候,mysql總是能夠立刻終止查詢。乙個典型的例子就是當使用了limit 子句的時候。
等值傳播。如果兩個列的值通過等式關聯,那麼mysql能夠把其中乙個列的where條件傳遞到另一列上。
列表in()的比較。在很多的資料庫系統中,in()完全等同於多個or條件的子句,因為這兩者是完全等價的。但是在mysql中,它將in()列表中的資料先進行排序,然後通過二分查詢的方式來確定列表中的值是否滿足條件,這是乙個o(log n)複雜度的操作,等價轉換為or查詢的複雜度為o(n)。對於in()列表中有大量取值的時候,mysql的處理速度會更快。
上面列舉的並不是mysql優化器的全部,mysql還會做其他大量的優化,因此我們完全沒有必要嘗試「自己會比優化器更加聰明」,這樣不僅會讓查詢更加複雜而難以維護,並且最終收益可能為0.讓優化器按照自己的方式正常工作即可。
但是如果能夠確認優化器給出的並不是最佳選擇,並且清除背後的原理那麼也可以嘗試幫助優化器作進一步的優化。比如在查詢中新增hint提示,也可以重寫查詢或者重新設計庫表結構。
mysql在伺服器層有查詢優化器,但是沒有儲存資料和索引的統計資訊。統計資訊由儲存引擎實現,不同的儲存引擎可能會儲存不同的統計資訊或者按照不同的格式儲存統計資訊。
mysql中的「關聯(join)」比一般意義上理解的更加廣泛。總的來說,mysql認為任何乙個查詢都是一次「關聯」——並不僅僅是乙個查詢需要用到兩張表的匹配才叫關聯。
以union查詢為例mysql先將一系列的單個查詢結果放到乙個臨時表中,然後再重新讀出臨時表資料來完成union查詢。
當前mysql關聯執行的策略如下:mysql對任何關聯都執行巢狀迴圈關聯操作,即mysql現在乙個表中迴圈取出單條資料,然後再巢狀迴圈到下乙個表中尋找匹配的行,依次下去,直到找到所有表中匹配的行為止。然後根據各個表匹配的行,返回查詢中需要的各個列。mysql會嘗試在最後乙個關聯表中查詢到所有匹配的行,如果最後乙個關聯表無法找到更多的行以後,mysql就會返回上一層次關聯表,看是否能夠找到更多的匹配記錄,以此類推迭代執行。
和很多其他關係型資料庫不同,mysql並不會生成查詢位元組碼來執行查詢。mysql生成查詢的一棵指令書,然後通過儲存引擎執行完成這棵指令書並返回結果。最終的執行計畫包含了重構查詢的全部資訊
mysql優化器最重要的一部分就是關聯查詢優化,它決定了多個表關聯時的順序。通常多表關聯時,可以有多種不同的關聯順序來獲得相同的結果。
關聯查詢優化器則通過評估不同順序時的成本來選擇乙個代價最小的關聯順序。它會遍歷每乙個表然後逐個做巢狀迴圈計算每一棵可能的執行計畫樹的成本,最後返回乙個最優的執行計畫。
然而,如果有超過n個表的關聯,那麼需要檢查n的階乘種關聯順序。這被稱為可能的執行計畫的「搜尋空間」,搜尋空間的增長速度非常快,如果我們需要關聯10個表,那麼共有3628800種不同的關聯順序。
當搜尋空間非常大時,優化器會選擇使用「貪婪」搜尋的方式查詢「最優」的關聯順序。有時候,各個查詢的順序是不能隨意安排的,比如左連線等,這時候關聯優化器就可以根據這些規則大大減少搜尋空間。
無論如何排序都是乙個成本很高的操作,所以從效能上看,應該盡可能避免排序或者盡可能避免對大量資料進行排序。
當不能使用索引生成排序結果的時候,mysql需要自己進行排序。如果資料量小則在記憶體中進行,如果資料量大則需要使用磁碟,不過mysql將這個過程統一稱為檔案排序(filesort),即使完全是記憶體排序不需要任何磁碟檔案時也是如此。
如果需要排序的資料量小於「排序緩衝區」,mysql使用記憶體進行「快速排序」操作。如果記憶體不夠排序,那麼mysql會將資料分塊,對每個獨立的塊使用「快速排序」進行排序,將各個塊的排序結果存放在磁碟上然後將各個排好序的快進行合併,最終返回排序結果。
MySQL查詢執行的基礎
當希望mysql能夠以更高的效能執行查詢時,最好的辦法就是弄清楚mysql是如何優化和執行查詢的。一旦理解這一點,很多查詢優化實際上就是遵循一些原則讓優化器能夠按照預想的合理的方式執行。換句話說,是時候回頭看看我們之前討論的內容了 mysql執行乙個查詢的過程。當向mysql傳送乙個請求的時候,my...
php mysql查詢優化 MySQL查詢優化
在我們使用mysql資料庫時,比較常用也是查詢,包括基本查詢,關聯查詢,條件查詢等等,對於同乙個操作,sql語句的實現有很多種寫法,但是不同的寫法查詢的效能可能會有很大的差異。這裡主要介紹下select查詢優化的要點。1.使用慢查詢日誌去發現慢查詢。2.使用執行計畫去判斷查詢是否正常執行。3.總是去...
查詢執行的基礎
mysql的一般查詢流程如下 mysql客戶但和伺服器中間的通訊協議時 半雙工 的。因此當查詢語句較長時引數 max allowed packet 很重要。都是從資料庫中的快取獲取資料。可以通過對mysql的介面,進行設定取消緩衝。mysql的查詢狀態 show full processlist進行...