1. 程式人生 > >mongodb查詢語句效率分析

mongodb查詢語句效率分析

準備工作

  1. 安裝最新版的mongodb.
  2. 安裝免費的圖形客戶端Robo 3T
  3. 在資料庫local下建立一個名為test的collection
  4. 建立索引db.test.createIndex( { a: -1, b:-1 }, {name:"ab"})
  5. 準備一些資料
{_id:1, a:1, b:2}
{_id:2, a:1, b:2}
{_id:3, a:1, b:3}
{_id:4, a:1, b:3}
{_id:5, a:2, b:2}
{_id:6, a:2, b:2}
{_id:7, a:2, b:3}
{_id:8, a:2, b:3}

索引分析

db.test.find({a:1}).explain();

執行結果

{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "local.test",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "a" : {
                "$eq" : 1.0
            }
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "a" : -1.0,
                    "b" : -1.0
                },
                "indexName" : "ab",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "a" : [],
                    "b" : []
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "a" : [ 
                        "[1.0, 1.0]"
                    ],
                    "b" : [ 
                        "[MaxKey, MinKey]"
                    ]
                }
            }
        },
        "rejectedPlans" : []
    },
    "serverInfo" : {},
    "ok" : 1.0
}

關鍵引數說明

欄位 說明
queryPlanner.indexFilterSet 是否啟用了index filter, mongodb使用index filter來選擇索引
queryPlanner.winningPlan 優化器最終選擇的plan
queryPlanner.winningPlan.inputStage 查詢輸入的引數和索引
queryPlanner.winningPlan.inputStage.stage 所處的階段
COLLSCAN: 掃描collection
IXSCAN掃描索引
FETCH讀取文件
queryPlanner.winningPlan.inputStage.keyPattern 索引的格式, 與建立索引時的格式一致
queryPlanner.winningPlan.inputStage.indexBounds 查詢條件的約束值.
queryPlanner.rejectedPlans 被拒絕掉的候選plan

執行過程分析

db.test.find({a:1}).explain("executionStats");
{
    "queryPlanner" : { 略 },
    "executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 4,
        "executionTimeMillis" : 0,
        "totalKeysExamined" : 4,
        "totalDocsExamined" : 4,
        "executionStages" : {
            "stage" : "FETCH",
            "nReturned" : 4,
            "executionTimeMillisEstimate" : 0,
            "works" : 5,
            "advanced" : 4,
            "needTime" : 0,
            "needYield" : 0,
            "saveState" : 0,
            "restoreState" : 0,
            "isEOF" : 1,
            "invalidates" : 0,
            "docsExamined" : 4,
            "alreadyHasObj" : 0,
            "inputStage" : {
                "stage" : "IXSCAN",
                "nReturned" : 4,
                "executionTimeMillisEstimate" : 0,
                "works" : 5,
                "advanced" : 4,
                "needTime" : 0,
                "needYield" : 0,
                "saveState" : 0,
                "restoreState" : 0,
                "isEOF" : 1,
                "invalidates" : 0,
                "keyPattern" : {
                    "a" : -1.0,
                    "b" : -1.0
                },
                "indexName" : "ab",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "a" : [],
                    "b" : []
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "a" : [ 
                        "[1.0, 1.0]"
                    ],
                    "b" : [ 
                        "[MaxKey, MinKey]"
                    ]
                },
                "keysExamined" : 4,
                "seeks" : 1,
                "dupsTested" : 0,
                "dupsDropped" : 0,
                "seenInvalidated" : 0
            }
        }
    },
    "serverInfo" : {},
    "ok" : 1.0
}

關鍵欄位說明

欄位 說明
executionStats.totalKeysExamined 遍歷索引的次數
executionStats.totalDocsExamined 遍歷文件的次數
executionTimeMillisEstimate 預測需要執行的時間

遍歷的次數越多, 遍歷肯定越慢. 本例中使用了索引, 有4條滿足條件的文件, 所有遍歷次數都是4.

不使用索引

db.test.find({b:2}).explain("executionStats");
{
    "executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 4,
        "executionTimeMillis" : 0,
        "totalKeysExamined" : 0,
        "totalDocsExamined" : 8,
    },
}

db.test.find({b:2})無法使用索引{a:1, b:1}, 所以沒有遍歷索引, 然後遍歷了整個collection

只返回索引資料

db.test.find({a:2}, {_id:0, a:1, b:1}).explain("executionStats");
{
    "executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 4,
        "executionTimeMillis" : 0,
 	"totalKeysExamined" : 4,
        "totalDocsExamined" : 0,
        }
    },
}

本例要mongodb只返回a, b兩次欄位, 而這兩個欄位剛好建立了索引, 不需要再讀取document, 所以沒有遍歷文件.

總結

mongodb中的索引與mysql的索引的行為非常相似