MongoDB 執行計畫 優化器簡介 上

2021-08-28 13:13:59 字數 3716 閱讀 3077

最近,由於工作需求去了解一下query是如何在mongodb內部進行處理,從而丟給儲存引擎的。裡面涉及了query執行計畫和優化器的相關**,mongodb整體思路設計的乾淨利落,有些地方深入挖一下其實還是能有些優化點的。本文會涉及一條query被parse之後一路走到引擎之前,都做了那些事情,分析基於mongodb v3.4.6**。由於篇幅過長,文章分為上下兩篇,分別介紹執行計畫 & 優化器和query具體的執行器。

名詞定義:

下圖主要描述了query在執行層的邏輯,其他模組的邏輯進行了精簡:

在此流程中:

本文後續以mongodb find命令為基礎,介紹執行計畫。update和delete也需要執行計畫,生成原理類似。

下面是乙個標準的find查詢協議包,紅框內是涉及查詢的基本運算元如:過濾條件filter運算元、sort排序運算元、投影運算元等等,其他是查詢的一些屬性,mongodb查詢區別於sql,沒有那麼複雜的語法和語**析,各個運算元被結構化的儲存到協議標準裡面,所以普通的查詢也直接可以取出。

後續plan會在這些運算元上做邏輯處理、優化再連線各個運算元,並生成一顆可以執行的樹狀資料結構

上述query中各個運算元使用bson結構表示的邏輯表示式,這裡會被先標準化成canonicalquery。主要涉及collatormatchexpression的生成。collator是使用者可以自定義的除了bytecomparator(逐字節比較排序)之外的比較方法,比如內建的中文比較。collator需要和filter裡的邏輯表示式相關聯(比如$gt大於運算)。

matchexpression是將filter運算元裡每個邏輯運算轉換成各個型別的表示式(gt,et,lt,and,or...),構成乙個表示式tree結構,頂層root是乙個andmatchexpression,如果含有and、or、nor,tree的深度就+1. 這個表示式tree會用做以後過濾記錄。

著這個過程裡會做一些簡單的等價代換的優化:

(來自於網路)

find/update/delete通過.explain()函式可以列印query生成的執行計畫, explain(「executionstats」)會列印更多的統計資訊。

上圖中比較關鍵的資訊:

在生成執行計畫之前,這裡有一些短路的優化。針對oplog掃瞄場景(oplogreplay)和_id主鍵查詢做了特例化,如果是oplogreplay則直接生成按ts欄位的collectionscan。如果是主鍵等值查詢,則生成idhack,直接查詢主鍵。生成執行的過程,本質上是通過query的查詢條件去匹配對應collection上的索引,然後根據相關性生成不同索引組合的不同執行路徑,每乙個索引規則都可能對應乙個執行計畫,或者是全表掃瞄collectionscan這裡選取索引有個規則:

1). 如果查詢帶_id主鍵索引,這直接選主鍵索引

2). 優先走覆蓋索引,即查詢條件帶該索引,並且projection運算元下只選擇該field的資料(不用二次fetch資料)

3). 如果既有唯一索引和普通索引,則優先使用該唯一索引(此處猜測應該是唯一索引命中概率更高,因為同一條記錄只出現一次)

4). 如果都是唯一索引,則first win(此處測試應該是按index name做了排序)

5). 如果都是普通索引或者索引之間有覆蓋,則會根據多個索引生成多個執行路徑,並生成多個執行計畫。

所以生成執行計畫其實就是匹配各個索引,然後按照這個索引的訪問方式,生成訪問資料的各個步驟,最終得到資料。如果最終生成了多個plan,則讓optimizer去選。

優化器是乙個很大的話題,各個傳統資料庫和newsql在這個地方都下了不少功夫,甚至說優化器的好壞直接決定了查詢效能。本文不在這裡介紹過多的優化器知識,涵蓋太廣。mongodb使用了一種類似cbo(cost based optimizer)的優化策略(同型別的還有rbo和hbo)。但和傳統的mysql的cbo有些不太一樣,mysql會採集一些引擎層索引的stats資訊,如條數、cardinality(稀疏度)等,然後根據stats估算執行計畫代駕。mongodb optimizer在評估時會touch資料,獲得乙個執行時資訊再去結合估算,進行plan的打分,得分最高的就是最優的。

optimizer分為logical邏輯優化和physical物理優化,邏輯優化在上面canonicalquery時已經做了,這裡只涉及物理優化。optimizer會把所有的plan都執行一小部分資料,在執行終會統計掃瞄次數、獲得結果次數等stats指標,然後根據該指標進行score計算,核心的幾個步驟如下:

所以最後score為:

選出的plan會進入plancache下次同樣queryshape的語句,會命中cache。這裡cache即使命中了,也不是完全無代價,是要去碰資料再去evaluate一次,如果猜測準確,則繼續使用cached plan。

網上有篇文章分享了由於不正確的plancache導致慢查的case有興趣可以看下

1). optimizer採用touch資料的方式,預設配置下,最少掃瞄100次結果,最大掃瞄max(10000, colletion_total_records * 0.3)次索引,在某些命中率很低的場景下,對io和資料量的影響還是很大。雖然後plancache能減少同一queryshape的開銷,但是plancache邏輯中本身同樣也要touch小部分資料,開銷還是有的。而且如果plancache的結果有可能已經不在適合當前查詢,比如資料的分布已經有了不小的變化,這時候是需要等到觸發replan的條件或者ddl的invalidate cache。

當然這麼做也有自己的道理,實現相對簡單,儲存引擎和server之間不用互訪index的分布資料,也省去了維護cardinality準確性的代價。

2). 現在優化器score機制本質上還是produtivity影響最大,該指標反應的index掃瞄和index讀取效率方面。其實還有很多方面可以考慮,比如index 的記憶體占用開銷,掃瞄時btree遍歷比較的cpu開銷(int型別一定比string型別小,不過mongo的index是無型別的),也應該計算在讀取開銷內。或者是類似mysql 8 的新機制,如果page在buffer pool已經存在,則優先選,這樣可以選擇盡量都在記憶體裡已經存在的index,減少io的開銷。

oracle 優化器 執行計畫

1 優化器種類 rule choose first rows n first rows all rows 10g後預設 2 訪問表的方法 全表掃瞄 table access full rowid掃瞄 table access by user rowid table access by index r...

優化器執行計畫選擇

1 資料準備 create table test1 as select d.trunc dbms random.value 0,100 as ran val from dba objects d 2 效能改善 2.1 寫法一 優化器還是很智慧型的,走了hash filter篩選,避開了filter連...

MongoDB檢視執行計畫

一 概述 mongodb中的explain 函式可以幫助我們檢視查詢相關的資訊,查詢分析可以確保我們建立的索引是否有效,是查詢語句效能分析的重要工具。二 explain 基本用法 explain 的用法是必須放在最後面,語法如下 db.collecton.find explain explain 常...