1

我在一个集合上有多个索引,如下所示。特别是我想要一个查询使用"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
    }
}

在这里,我有一个单独的 ' ' 索引(基于 TTL 的索引)和一个以 ' ' 和 ' ' 作为前两个键gTs的复合索引。( )gTsRE_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"
}

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

4

1 回答 1

2

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

据我所知,这应该使用“gTs_1_RE_H_1_l_1”,但令人惊讶的是,它使用的是“gTs_1”,如此输出中提到的:

这并不奇怪。您应该查看有关索引的文档,尤其是有关排序的部分。虽然您在这里不请求排序,但您使用的是范围查询($lte及其兄弟),这非常相似。您至少需要将索引的顺序更改为 ,以便RE_HgTs出现 equals 约束的索引,然后是范围查询。

于 2014-03-19T09:53:54.390 回答