使用正则表达式和排序的Mongodb简单前缀查询很慢

时间:2012-10-23 15:37:19

标签: regex mongodb sorting indexing

我坚持使用这个简单的前缀查询。虽然Mongo docs表示使用前缀regex格式(/ ^ a /)可以获得相当不错的性能,但是当我尝试对结果进行排序时,查询速度非常慢:

940毫秒

  

db.posts.find({hashtags:/ ^ noticias /})。limit(15).sort({rank:-1})。hint('hashtags_1_rank_-1')。explain()

{
"cursor" : "BtreeCursor hashtags_1_rank_-1 multi",
"isMultiKey" : true,
"n" : 15,
"nscannedObjects" : 142691,
"nscanned" : 142692,
"nscannedObjectsAllPlans" : 142691,
"nscannedAllPlans" : 142692,
"scanAndOrder" : true,
"indexOnly" : false,
"nYields" : 1,
"nChunkSkips" : 0,
"millis" : 934,
"indexBounds" : {
    "hashtags" : [
        [
            "noticias",
            "noticiat"
        ],
        [
            /^noticias/,
            /^noticias/
        ]
    ],
    "rank" : [
        [
            {
                "$maxElement" : 1
            },
            {
                "$minElement" : 1
            }
        ]
    ]
},
"server" : "XRTZ048.local:27017"
}

但是,同一查询的未排序版本速度非常快:

0毫秒

  

db.posts.find({hashtags:/ ^ noticias /})。limit(15).hint('hashtags_1_rank_-1')。explain()

{
"cursor" : "BtreeCursor hashtags_1_rank_-1 multi",
"isMultiKey" : true,
"n" : 15,
"nscannedObjects" : 15,
"nscanned" : 15,
"nscannedObjectsAllPlans" : 15,
"nscannedAllPlans" : 15,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
    "hashtags" : [
        [
            "noticias",
            "noticiat"
        ],
        [
            /^noticias/,
            /^noticias/
        ]
    ],
    "rank" : [
        [
            {
                "$maxElement" : 1
            },
            {
                "$minElement" : 1
            }
        ]
    ]
},
"server" : "XRTZ048.local:27017"

}

如果我删除正则表达式并排序,查询也很快:

0毫秒

  

db.posts.find({hashtags:'noticias'})。limit(15).sort({rank:-1})。hint('hashtags_1_rank_-1')。explain()

{
"cursor" : "BtreeCursor hashtags_1_rank_-1",
"isMultiKey" : true,
"n" : 15,
"nscannedObjects" : 15,
"nscanned" : 15,
"nscannedObjectsAllPlans" : 15,
"nscannedAllPlans" : 15,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
    "hashtags" : [
        [
            "noticias",
            "noticias"
        ]
    ],
    "rank" : [
        [
            {
                "$maxElement" : 1
            },
            {
                "$minElement" : 1
            }
        ]
    ]
},
"server" : "XRTZ048.local:27017"

}

似乎使用正则表达式和排序使Mongo扫描大量记录。但是,如果我不使用正则表达式,sort只扫描15。这有什么不对?

1 个答案:

答案 0 :(得分:6)

explain输出中的scanAndOrder: true表示查询必须检索文档,然后在返回输出之前在内存中对它们进行排序。这是一项昂贵的操作,会对查询的性能产生影响。

解释输出中scanAndOrder: true的存在以及nscannedn的差异表明查询未使用最佳索引。在这种情况下,它似乎需要进行收集扫描。您可以通过在sort条件中包含索引键来缓解此问题。从我的测试:

db.posts.find({hashtags: /^noticias/ }).limit(15).sort({hashtags:1, rank : -1}).explain()

不需要扫描和订单,并返回您要查找的记录数量的nnscanned。这也意味着对hashtags键进行排序,这可能对您有用,也可能没有用,但应该提高查询的性能。