MongoDB选择非常糟糕的索引

时间:2015-02-03 15:24:43

标签: mongodb mongodb-query

我正在运行MongoDB 2.6.7版。我有一个大约有700万份文件的集合。每个文档上都有一个guid字段,这是唯一的。这是一个示例查询,我希望它应该使用guid索引,而是在不同的索引上使用一些疯狂的查询:

2015-02-02T23:05:13.349+0000 [conn6716672] query MyDB.persistentObject query: 
{ query: 
{ guid: { $in: [ "some_guid" ] }, 
ownerId: { $in: [ 0, 1, 1025252577, 994090559, 1317724, 1088410057, 
1125454113, 1122731922, 994089725, 1122732678, 1317394, 1129549288,1122731600, 
1312755, 1115032827, 1122461088, 1315404, 1025251224, 1124535620, 1059802590, 
1124023810, 1125620352, 991434980, 1115022865, 1115031571, 1124514149, 
1124534953, 1124534178, 1126176542, 1124533461, 149095604, 810047314, 
1069908537 ] } }, 
orderby: { updated: -1 }, 
planSummary: IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 },
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 },
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 }, IXSCAN { ownerId: 1.0, updated: -1.0 }, 
IXSCAN { ownerId: 1.0, updated: -1.0 } 
ntoreturn:500 ntoskip:0 nscanned:6739394 nscannedObjects:6739394 
keyUpdates:0 numYields:7434 locks(micros) r:374790754 nreturned:1 reslen:55 274222ms

以下是该集合的索引列表:

shard1:PRIMARY> db.MyDB.getIndexes()
[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "MyDB.persistentObject"
    },
    {
        "v" : 1,
        "key" : {
            "id" : 1,
            "updated" : -1
        },
        "name" : "id_updated_index",
        "ns" : "MyDB.persistentObject",
        "dropDups" : false,
        "sparse" : false
    },
    {
        "v" : 1,
        "key" : {
            "guid" : 1
        },
        "name" : "guid",
        "ns" : "MyDB.persistentObject",
        "dropDups" : false,
        "sparse" : false
    },
    {
        "v" : 1,
        "key" : {
            "ownerId" : 1,
            "updated" : -1
        },
        "name" : "ownerId_1_updated_-1",
        "ns" : "MyDB.persistentObject"
    }
]

由于只有一个guid请求,但许多ownerIds,我希望使用guid索引。如果使用它,将导致nscanned=1并且结果非常快。相反,选择了一个非常浪费的指数。在不同的查询中反复选择这个坏索引,mongo实例变得完全残缺。

db.stats():

{
    "db" : "MyDB",
    "collections" : 7,
    "objects" : 6761839,
    "avgObjSize" : 496.46051968998376,
    "dataSize" : 3356986104,
    "storageSize" : 3918581760,
    "numExtents" : 28,
    "indexes" : 14,
    "indexSize" : 983450160,
    "fileSize" : 10666115072,
    "nsSizeMB" : 16,
    "dataFileVersion" : {
        "major" : 4,
        "minor" : 5
    },
    "extentFreeList" : {
        "num" : 10,
        "totalSize" : 475508736
        },
    "ok" : 1
}

db.serverStatus()MEM:

{
    "bits" : 64,
    "resident" : 946,
    "virtual" : 38232,
    "supported" : true,
    "mapped" : 18409,
    "mappedWithJournal" : 36818
}

正确选择guid的示例解释计划。大多数时候,当我运行解释时,它会做我想要的。但是,似乎每天都会发生一些事情,它开始选择糟糕的指数并最终陷入死亡螺旋。

db.persistentObject.find({ guid: { $in: [ "some_guid" ] }, ownerId: { $in: [ 0, 1, 1025252577, 994090559, 1317724, 1088410057, 1125454113, 1122731922, 994089725, 
1122732678, 1317394, 1129549288,1122731600, 1312755, 1115032827, 1122461088, 1315404, 1025251224, 1124535620, 1059802590, 1124023810, 1125620352, 991434980, 1115022865, 
1115031571, 1124514149, 1124534953, 1124534178, 1126176542, 1124533461, 149095604, 810047314, 1069908537 ]}, orderby: { updated: -1 }}).explain()
{
    "cursor" : "BtreeCursor guid",
    "isMultiKey" : false,
    "n" : 0,
    "nscannedObjects" : 1,
    "nscanned" : 1,
    "nscannedObjectsAllPlans" : 4,
    "nscannedAllPlans" : 4,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 1,
    "nChunkSkips" : 0,
    "millis" : 20,
    "indexBounds" : {
        "guid" : [
            [
                "some_guid",
                "some_guid"
            ]
        ]
    },
    "server" : "myServer:27018",
    "filterSet" : false,
    "stats" : {
        "type" : "KEEP_MUTATIONS",
        "works" : 3,
        "yields" : 1,
        "unyields" : 1,
        "invalidates" : 0,
        "advanced" : 0,
        "needTime" : 1,
        "needFetch" : 0,
        "isEOF" : 1,
        "children" : [
            {
                "type" : "FETCH",
                "works" : 2,
                "yields" : 1,
                "unyields" : 1,
                "invalidates" : 0,
                "advanced" : 0,
                "needTime" : 1,
                "needFetch" : 0,
                "isEOF" : 1,
                "alreadyHasObj" : 0,
                "forcedFetches" : 0,
                "matchTested" : 0,
                "children" : [
                    {
                        "type" : "IXSCAN",
                        "works" : 2,
                        "yields" : 1,
                        "unyields" : 1,
                        "invalidates" : 0,
                        "advanced" : 1,
                        "needTime" : 0,
                        "needFetch" : 0,
                        "isEOF" : 1,
                        "keyPattern" : "{ guid: 1 }",
                        "isMultiKey" : 0,
                        "boundsVerbose" : "field #0['guid']: [\"some_guid\", \"some_guid\"]",
                        "yieldMovedCursor" : 0,
                        "dupsTested" : 0,
                        "dupsDropped" : 0,
                        "seenInvalidated" : 0,
                        "matchTested" : 0,
                        "keysExamined" : 1,
                        "children" : [ ]
                    }
                ]
            }
        ]
    }
}

1 个答案:

答案 0 :(得分:0)

它似乎已选择索引ownerId_1_updated_-1作为查询的最佳候选者,因为这可以帮助查询的排序部分。这仍将导致扫描大量文档,因为它必须与guid字段匹配。

尝试将guid字段添加到ownerId_1_updated_-1索引

 {
        "v" : 1,
        "key" : {
            "guid" : 1,
            "ownerId" : 1,
            "updated" : -1
        },
        "name" : "guid_1_ownerId_1_updated_-1",
        "ns" : "MyDB.persistentObject"
    }