MySQL查询执行的基础——查询优化处理
查詢的生命周期的下一步是將一個SQL轉換成一個可執行計劃,MySQL再按照這個計劃和存儲引擎進行交互
語法解析器和預處理
首先,MySQL通過關鍵詞將SQL語句進行解析,并生成一顆對應的“解析樹”。MySQL解析器將使用MySQL語法規則驗證和解析查詢。比如是否使用了錯誤的關鍵字,關鍵字的順序是否正確,或者引號是否能夠正確的前后匹配。
預處理器則會根據一些MySQL規則進一步檢查解析樹是否合法。它會檢查數據表和數據列是否存在,還會解析名字和別名,看看它們是否存在歧義。
查詢優化器
當語法樹被認為是合法的時候,將轉由優化器去轉化成執行計劃。一條查詢可以有很多種執行方式,最后都返回相同的結果。優化器的作用就是找到這其中最好的執行計劃。
MySQL使用的是基于成本的優化器,它將會嘗試預測一個查詢使用某種執行計劃時的成本,并選擇其中成本最小的那一個??梢酝ㄟ^查詢當前會話的“Last_query_cost”的值來的值MySQL計算的當前查詢的成本。
這個結果表示MySQL的優化器認為大概需要做1040個數據頁的隨機查找才能夠完成上面的查詢。這是根據一系列的統計信息計算的來的。優化器在評估成本時并不會考慮任何層面的緩存,它假設讀取任何數據都需要一次磁盤I/O。
有很多種情況會導致MySQL優化器選擇錯誤的執行計劃,如下所示:
- 統計信息不準確。 MySQL依賴存儲引擎提供的統計信息來評估成本,但是有的存儲引擎提供的信息偏差非常大。比如InnoDB因為使用了MVCC架構,并不能維護一個數據表的行數的精確統計信息。
- 執行計劃中的成本估算不等同于實際執行的成本。 所以及時統計信息精準,優化器給出的執行計劃也可能不是最優的。比如某個執行計劃雖然需要讀取很多的頁面,但是如果這些頁面都是順序讀取獲取已經在內存中了的話,那么訪問它的成本將非常小。
- MySQL的最優可能和我們想的最優是不同的。 我們理解的最優是執行時間盡可能短,但是MySQL只是基于其成本模型選擇最優的執行計劃,而有些時候并不是最快的執行方式。
- MySQL從不考慮其他正在并發執行的查詢,這可能會影響當前查詢的速度。
- MySQL并不是任何時候都基于成本的優化。 有時候它也會基于一些固定的規則,比如存在全文搜索的MATCH()子句時,MySQL會選擇使用全文索引而不是使用其他更快的索引或者WHERE條件。
- MySQL不會考慮不受其控制的操作的成本,比如執行存儲過程或者用戶自定義函數的成本。
- 優化器有時候無法去估算所有可能的執行計劃,所以可能會錯過實際上最優的執行計劃。
MySQL的查詢優化器是一個非常復雜的不見,它使用了很多優化策略來生成一個最優的執行計劃。優化策略可以簡單的分為兩種,一種是靜態優化,一種是動態優化。
靜態優化可以直接對解析樹進行分析,并完成優化。例如通過一些簡單的袋鼠變換將WHERE條件轉換成另一種等價形式,可以認為是一種“編譯時優化”。
動態優化則是和查詢的上下文相關,也可能和很多其他因素有關,這些需要在每次查詢時重新評估,可以認為是“運行時優化”
。
在執行語句和存儲過程的時候,動態優化和靜態優化的區別很重要。MySQL對查詢的靜態優化只需要做一次,但是對查詢的動態優化則在每次執行時都需要重新評估。有時候甚至在查詢的執行過程中也會重新優化。
下面是一些MySQL可以處理的優化類型:
上面列舉的并不是MySQL優化器的全部,MySQL還會做其他大量的優化,因此我們完全沒有必要嘗試“自己會比優化器更加聰明”,這樣不僅會讓查詢更加復雜而難以維護,并且最終收益可能為0.讓優化器按照自己的方式正常工作即可。
但是如果能夠確認優化器給出的并不是最佳選擇,并且清除背后的原理那么也可以嘗試幫助優化器作進一步的優化。比如在查詢中添加hint提示,也可以重寫查詢或者重新設計庫表結構。
數據和索引的統計信息
MySQL在服務器層有查詢優化器,但是沒有保存數據和索引的統計信息。統計信息由存儲引擎實現,不同的存儲引擎可能會存儲不同的統計信息或者按照不同的格式存儲統計信息。
MySQL如何執行關聯操作
MySQL中的“關聯(join)”比一般意義上理解的更加廣泛??偟膩碚f,MySQL認為任何一個查詢都是一次“關聯”——并不僅僅是一個查詢需要用到兩張表的匹配才叫關聯。
以UNION查詢為例MySQL先將一系列的單個查詢結果放到一個臨時表中,然后再重新讀出臨時表數據來完成UNION查詢。
當前MySQL關聯執行的策略如下:MySQL對任何關聯都執行嵌套循環關聯操作,即MySQL現在一個表中循環取出單條數據,然后再嵌套循環到下一個表中尋找匹配的行,依次下去,直到找到所有表中匹配的行為止。然后根據各個表匹配的行,返回查詢中需要的各個列。MySQL會嘗試在最后一個關聯表中查找到所有匹配的行,如果最后一個關聯表無法找到更多的行以后,MySQL就會返回上一層次關聯表,看是否能夠找到更多的匹配記錄,以此類推迭代執行。
執行計劃
和很多其他關系型數據庫不同,MySQL并不會生成查詢字節碼來執行查詢。MySQL生成查詢的一棵指令書,然后通過存儲引擎執行完成這棵指令書并返回結果。最終的執行計劃包含了重構查詢的全部信息
關聯查詢優化器
MySQL優化器最重要的一部分就是關聯查詢優化,它決定了多個表關聯時的順序。通常多表關聯時,可以有多種不同的關聯順序來獲得相同的結果。
關聯查詢優化器則通過評估不同順序時的成本來選擇一個代價最小的關聯順序。它會遍歷每一個表然后逐個做嵌套循環計算每一棵可能的執行計劃樹的成本,最后返回一個最優的執行計劃。
然而,如果有超過n個表的關聯,那么需要檢查n的階乘種關聯順序。這被稱為可能的執行計劃的“搜索空間”,搜索空間的增長速度非???#xff0c;如果我們需要關聯10個表,那么共有3628800種不同的關聯順序。
當搜索空間非常大時,優化器會選擇使用“貪婪”搜索的方式查找“最優”的關聯順序。有時候,各個查詢的順序是不能隨意安排的,比如左連接等,這時候關聯優化器就可以根據這些規則大大減少搜索空間。
排序優化
無論如何排序都是一個成本很高的操作,所以從性能上看,應該盡可能避免排序或者盡可能避免對大量數據進行排序。
當不能使用索引生成排序結果的時候,MySQL需要自己進行排序。如果數據量小則在內存中進行,如果數據量大則需要使用磁盤,不過MySQL將這個過程統一稱為文件排序(filesort),即使完全是內存排序不需要任何磁盤文件時也是如此。
如果需要排序的數據量小于“排序緩沖區”,MySQL使用內存進行“快速排序”操作。如果內存不夠排序,那么MySQL會將數據分塊,對每個獨立的塊使用“快速排序”進行排序,將各個塊的排序結果存放在磁盤上然后將各個排好序的快進行合并,最終返回排序結果。
轉載于:https://www.cnblogs.com/AmosH/p/10256407.html
總結
以上是生活随笔為你收集整理的MySQL查询执行的基础——查询优化处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java垃圾回收机制的理解
- 下一篇: 仙人掌找环板子