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

jai*_*ime 7 regex sorting indexing mongodb

我坚持使用这个简单的前缀查询.虽然Mongo文档声明通过使用前缀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"
}
Run Code Online (Sandbox Code Playgroud)

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

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"
Run Code Online (Sandbox Code Playgroud)

}

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

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"
Run Code Online (Sandbox Code Playgroud)

}

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

And*_*ere 6

scanAndOrder: true在解释输出指示查询是有检索文档,然后返回输出之前在内存中进行排序.这是一项昂贵的操作,会对查询的性能产生影响.

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

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

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