MongoDB 提供 db.collection.explain(), cursort.explain() 及 explain 命令獲取查詢計劃及查詢計劃執行統計信息。
explain 結果將查詢計劃以階段樹的形式呈現。 每個階段將其結果(文檔或索引鍵)傳遞給父節點。 葉節點訪問集合或索引。 中間節點操縱由子節點產生的文檔或索引鍵。 根節點是MongoDB從中派生結果集的最后階段。
階段操作描述,例:
- COLLSCAN 集合掃描
- IXSCAN 索引掃描
- FETCH 檢出文檔
- SHARD_MERGE 合并分片中結果
- SHARDING_FILTER 分片中過濾掉孤立文檔
- LIMIT 使用limit 限制返回數
- PROJECTION 使用 skip 進行跳過
- IDHACK 針對_id進行查詢
- COUNT 利用db.coll.explain().count()之類進行count運算
- COUNTSCAN count不使用Index進行count時的stage返回
- COUNT_SCAN count使用了Index進行count時的stage返回
- SUBPLA 未使用到索引的$or查詢的stage返回
- TEXT 使用全文索引進行查詢時候的stage返回
- PROJECTION 限定返回字段時候stage的返回
- …
explain 操作返回結果詳解
queryPlanner
queryPlanner 顯示的是被查詢優化器選擇出來的查詢計劃。
以下未分片集合 explain 操作結果如下:
{"queryPlanner" : {"plannerVersion" : <int>,"namespace" : <string>,"indexFilterSet" : <boolean>,"parsedQuery" : {...},"winningPlan" : {"stage" : <STAGE1>,..."inputStage" : {"stage" : <STAGE2>,..."inputStage" : {...}}},"rejectedPlans" : [<candidate plan 1>,...]}
- queryPlanner.namespace 一個字符串,指定運行查詢的命名空間(即.)。
- queryPlanner.indexFilterSet boolan值,表示MongoDB 對于此query shape 是否使用了索引過濾器。
- queryPlanner.winningPlan 文檔類型,詳細顯示查詢優化程序選擇的查詢計劃。
- winningPlan.stage 階段名稱。每個階段都有每個階段特有的信息。 例如,IXSCAN 階段將包括索引邊界以及特定于索引掃描的其他數據。 如果階段具有子階段或多個子階段,則階段將具有inputStage 或 inputStages。
- winningPlan.inputStage 描述子階段的文檔。它為其父級提供文檔或索引鍵。 如果父級只有一個子級,則該字段存在。
- winningPlan.inputStages 描述子階段的數組。子階段為父階段提供文檔或索引鍵。 如果父級具有多個子節點,則該字段存在。 例如,$or 表達式或索引交集的階段消耗來自多個源的輸入。
- queryPlanner.rejectedPlans 查詢優化器考慮和拒絕的候選計劃數組。 如果沒有其他候選計劃,則該數組可以為空。
對于分片集合,獲勝計劃包括分每個訪問的分片的計劃信息數組。
executionStats
executionStats 返回的是獲勝計劃執行相關信息。必須在 executionStats 或 allPlansExecution 詳細模式下運行explain才顯示executionStats 相關信息。
要捕獲選擇執行計劃期間執行相關信息,必須使用 allPlansExecution 模式運行。
executionStats 模式 explain 實例:
db.products.explain("executionStats").find({ quantity: { $gt: 50 }, category: "apparel" }
)
allPlansExecution 模式 explain 實例:
db.products.explain("allPlansExecution").update({ quantity: { $lt: 1000}, category: "apparel" },{ $set: { reorder: true } }
)
以下未分片集合 explain 操作結果如下:
"executionStats" : {"executionSuccess" : <boolean>,"nReturned" : <int>,"executionTimeMillis" : <int>,"totalKeysExamined" : <int>,"totalDocsExamined" : <int>,"executionStages" : {"stage" : <STAGE1>"nReturned" : <int>,"executionTimeMillisEstimate" : <int>,"works" : <int>,"advanced" : <int>,"needTime" : <int>,"needYield" : <int>,"isEOF" : <boolean>,..."inputStage" : {"stage" : <STAGE2>,..."nReturned" : <int>,"executionTimeMillisEstimate" : <int>,"keysExamined" : <int>,"docsExamined" : <int>,..."inputStage" : {...}}},"allPlansExecution" : [{ <partial executionStats1> },{ <partial executionStats2> },...]
}
- executionStats 描述獲勝計劃完整的查詢執行信息。 對于寫入操作,是指將要執行修改的信息,但不會真實修改數據庫。
- executionStats.nReturned 查詢條件匹配到的文檔數量。
- executionStats.executionTimeMillis 查詢計劃選擇和查詢執行所需的總時間(以毫秒為單位)。executionTimeMillis 對應于早期版本的MongoDB中cursor.explain() 返回的millis字段。
- executionStats.totalKeysExamined 掃描的索引條目數。totalKeysExamined 對應于早期版本的MongoDB中cursor.explain() 返回的 nscanned字段。
- executionStats.totalDocsExamined 掃描的文檔數。totalDocsExamined 對應于早期版本的MongoDB中cursor.explain() 返回的 nscannedObjects字段。
- executionStats.executionStages 階段樹形式展示獲勝計劃完整的執行信息。即,一個階段可以有一個inputStage或多個inputStages。
-
executionStats.executionStages.works 查詢執行階段執行的“工作單元”的數量。 查詢執行階段將其工作分為小單元。 “工作單位”可能包括檢查單個索引鍵,從集合中提取單個文檔,將投影應用于單個文檔或執行內部記賬。
-
executionStats.executionStages.advanced 返回到父階段的結果數。
-
executionStats.executionStages.needTime 未將中間結果返回給其父級的工作循環數。 例如,索引掃描階段可以花費一個工作周期來尋找索引中的新位置而不是返回索引關鍵字; 這個工作周期將計入explain.executionStats.executionStages.needTime而不是explain.executionStats.executionStages.advanced。
-
executionStats.executionStages.needYield 存儲層請求查詢系統產生鎖定的次數。
-
executionStats.executionStages.isEOF 執行階段是否已到達流的結尾:
- 如果為true或1,則執行階段已到達流末尾。
- 如果為false或0,則階段可能仍會返回結果。 例如,有限制的查詢,其執行階段包含LIMIT階段,其中查詢的輸入階段為IXSCAN。 如果查詢返回超過指定的限制,LIMIT階段將報告isEOF:1,但其基礎IXSCAN階段將報告isEOF:0。
-
executionStats.executionStages.inputStage.keysExamined 對于掃描索引的查詢執行階段(例如IXSCAN),keysExamined是在索引掃描過程中檢查的入站和越界鍵的總數。 如果索引掃描由單個連續范圍的鍵組成,則只需要檢查入站鍵。 如果索引邊界由若干鍵范圍組成,則索引掃描執行過程可以檢查越界鍵,以便從一個范圍的末尾跳到下一個范圍的開頭。
考慮以下示例,集合包含字段x值為1到100的100個文檔,其中索引字段為x:
for(var x=1;x<=100;x++){db.keys.insert({x:x}); } db.keys.ensureIndex({x:1}); db.keys.find( { x : { $in : [ 3, 4, 50, 74, 75, 90 ] } } ).explain( "executionStats" )
該查詢將掃描鍵3和4.然后它將掃描鍵5,檢測它是否超出界限,并跳到下一個鍵50。
繼續該過程,查詢掃描鍵3,4,5,50,51,74,75,76,90和91.鍵5,51,76和91是仍在檢查的越界鍵。 keysExamined的值為10。
-
executionStats.executionStages.inputStage.docsExamined 在查詢執行階段掃描的文檔數。
-
executionStats.allPlansExecution 包含在計劃選擇階段為獲勝和拒絕計劃捕獲的部分執行信息。 僅當explain在allPlansExecution詳細模式下運行時,該字段才會出現。
-
serverInfo
對于未分片的集合,MongoDB實例explain返回以下信息:
"serverInfo" : {"host" : <string>,"port" : <int>,"version" : <string>,"gitVersion" : <string>
}
對于分片集合,explain返回每個訪問的分片的serverInfo。
Sharded Collection
對于分片集合,explain在shards字段中返回每個訪問的分片的核心查詢規劃器和服務器信息:
{"queryPlanner" : {..."winningPlan" : {..."shards" : [{"shardName" : <shard>,<queryPlanner information for shard>,<serverInfo for shard>},...],},},"executionStats" : {..."executionStages" : {..."shards" : [{"shardName" : <shard>,<executionStats for shard>},...]},"allPlansExecution" : [{"shardName" : <string>,"allPlans" : [ ... ]},...]}
}
- queryPlanner.winningPlan.shards 每個訪問分片的queryPlanner和serverInfo的文檔數組。
- executionStats.executionStages.shards 包含每個訪問分片的executionStats的文檔數組。
兼容性的修改
在 3.0 版本中的修改。
explain 結果的格式和字段與以前的版本相比有所變化。 以下列出了一些主要差異。
集合掃描 VS 索引使用
如果查詢計劃程序選擇了集合掃描,則說明結果包括COLLSCAN階段。
如果查詢計劃程序選擇索引,則說明結果包括IXSCAN階段。 該階段包括諸如索引key的匹配,遍歷方向和索引邊界之類的信息。
在早期版本的MongoDB中,cursor.explain() 返回了光標字段,其值為:
用于集合掃描的BasicCursor,以及索引掃描的BtreeCursor <索引名稱> [<方向>]。
覆蓋查詢
當索引覆蓋查詢時,MongoDB可以匹配查詢條件并僅使用索引鍵返回結果; 即MongoDB不需要檢查集合中的文檔以返回結果。
當索引覆蓋查詢時,解釋結果的IXSCAN階段不是FETCH階段的后代,而在executionStats中,totalDocsExamined為0。
在早期版本的MongoDB中,cursor.explain() 返回indexOnly字段以指示索引是否覆蓋了查詢。
索引交叉
對于索引交集計劃,結果將包括AND_SORTED階段或AND_HASH階段,其中包含詳細說明索引的inputStages數組; 例如。:
{"stage" : "AND_SORTED","inputStages" : [{"stage" : "IXSCAN",...},{"stage" : "IXSCAN",...}]
}
在以前版本的MongoDB中,cursor.explain() 返回了游標字段,其中包含索引交叉點的復雜計劃。
$or 表達式
如果MongoDB使用$or 表達式的索引,則結果將包含OR階段,其中包含詳細說明索引的inputStages數組; 例如。:
{"stage" : "OR","inputStages" : [{"stage" : "IXSCAN",...},{"stage" : "IXSCAN",...},...]
}
在早期版本的MongoDB中,cursor.explain() 返回了詳細索引的子句數組。
Sort 階段
如果MongoDB可以使用索引掃描來獲取請求的排序順序,則結果將不包括SORT階段。 否則,如果MongoDB無法使用索引進行排序,則解釋結果將包括SORT階段。
在MongoDB 3.0之前,cursor.explain() 返回scanAndOrder字段以指定MongoDB是否可以使用索引順序返回排序結果。
總結
explain 希望看到的階段
Fetch+IDHACK
Fetch+ixscan
Limit+(Fetch+ixscan)
PROJECTION+ixscan
SHARDING_FILTER+ixscan
COUNT_SCAN
…
explain 不希望看到的階段
COLLSCAN(全表掃描),
SORT(使用sort但是無index),
不合理的SKIP,
SUBPLA(未用到index的$or),
COUNTSCAN
來自個人博客:學習園
http://www.xuexiyuan.cn/article/detail/179.html