Mongodb使用错误的索引

时间:2014-03-19 07:34:11

标签: mongodb mongodb-indexes compound-index

我在集合上有多个索引,如下所示。特别我希望查询使用"gTs_1_RE_H_1_l_1",但查询使用的是"gTs_1"

{
    "0" : {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "ns" : "week_raw_tweet_db.tweets",
        "name" : "_id_"
    },
    "1" : {
        "v" : 1,
        "key" : {
            "gTs" : 1
        },
        "ns" : "week_raw_tweet_db.tweets",
        "name" : "gTs_1",
        "expireAfterSeconds" : 604800
    },
    "2" : {
        "v" : 1,
        "key" : {
            "uN" : 1
        },
        "ns" : "week_raw_tweet_db.tweets",
        "name" : "uN_1"
    },
    "3" : {
        "v" : 1,
        "key" : {
            "gTs" : 1,
            "RE_H" : 1,
            "l" : 1
        },
        "ns" : "week_raw_tweet_db.tweets",
        "name" : "gTs_1_RE_H_1_l_1",
        "background" : 1
    }
}

这里我有一个关于' gTs'的索引。单独(基于TTL的索引)和带有' gTs'的复合索引和' RE_H'作为前两个键。 ("gTs_1_RE_H_1_l_1"

现在,我正在尝试执行此查询:

db.tweets.find( {

                    "RE_H" : NumberLong("484001755192636620"),                  
                    "gTs" : {
                        "$lte" : ISODate("2014-03-18T22:00:00Z"),
                        "$gte" : ISODate("2014-03-17T21:00:00Z")
                    }
                }).explain()

根据我的知识,这应该使用"gTs_1_RE_H_1_l_1",但令人惊讶的是它正在使用, "gTs_1"正如此输出所述:

{
    "cursor" : "BtreeCursor gTs_1",
    "isMultiKey" : false,
    "n" : 46508,
    "nscannedObjects" : 365746,
    "nscanned" : 365746,
    "nscannedObjectsAllPlans" : 370493,
    "nscannedAllPlans" : 370494,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 1,
    "nChunkSkips" : 0,
    "millis" : 1509,
    "indexBounds" : {
        "gTs" : [ 
            [ 
                ISODate("2014-03-17T21:00:00.000Z"), 
                ISODate("2014-03-18T22:00:00.000Z")
            ]
        ]
    },
    "server" : "Frrole-API1:27017"
}

但是,如果我提供一个提示,它确实会选择正确的索引。所以,如果我运行以下查询:

db.tweets.find( {

                    "RE_H" : NumberLong("484001755192636620"),                  
                    "gTs" : {
                        "$lte" : ISODate("2014-03-18T22:00:00Z"),
                        "$gte" : ISODate("2014-03-17T21:00:00Z")
                    }
                }).hint("gTs_1_RE_H_1_l_1").explain()

我得到以下输出:

/* 0 */
{
    "cursor" : "BtreeCursor gTs_1_RE_H_1_l_1",
    "isMultiKey" : true,
    "n" : 46508,
    "nscannedObjects" : 233224,
    "nscanned" : 233541,
    "nscannedObjectsAllPlans" : 233224,
    "nscannedAllPlans" : 233541,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 3,
    "nChunkSkips" : 0,
    "millis" : 1874,
    "indexBounds" : {
        "gTs" : [ 
            [ 
                true, 
                ISODate("2014-03-18T22:00:00.000Z")
            ]
        ],
        "RE_H" : [ 
            [ 
                NumberLong(484001755192636620), 
                NumberLong(484001755192636620)
            ]
        ],
        "l" : [ 
            [ 
                {
                    "$minElement" : 1
                }, 
                {
                    "$maxElement" : 1
                }
            ]
        ]
    },
    "server" : "Frrole-API1:27017"
}

有人可以帮我理解发生了什么!

1 个答案:

答案 0 :(得分:1)

从输出中可以看出,使用更简单索引的查询更快大约300ms,这就是mongodb使用该索引的原因。 MongoDB的优化并没有尝试理解查询路径并猜测它的速度有多快,它只是执行不同的查询,而测量哪一个最快。您的MongoDB已经了解到使用简单的gTs索引会更快。它会不时通过并行运行不同的查询来自动测试它。

  

根据我的知识,这应该使用" gTs_1_RE_H_1_l_1",但令人惊讶的是它正在使用," gTs_1"如此输出所述:

这并不奇怪。您应该查看有关索引的文档,尤其是the section about sorting。虽然您不在此处请求排序,但您正在使用范围查询($lte及其兄弟姐妹),这非常相似。您至少需要将索引的顺序更改为RE_HgTs,使得等于约束的索引首先出现,然后是范围查询。