Javascript 高效的mongodb排序和正则表达式查询
这是monodb中的查询,需要花费很多时间。如何有效地查询这个问题?下面是上述查询的explain()输出。我在收集位置总共有442161个文档。我必须做一些前缀搜索。我已经在(国家/地区,docType),(地区,docType),(城市,docType)和(国家/地区,地区,城市)中做了索引。我的mongo版本是2.4.9Javascript 高效的mongodb排序和正则表达式查询,javascript,mongodb,Javascript,Mongodb,这是monodb中的查询,需要花费很多时间。如何有效地查询这个问题?下面是上述查询的explain()输出。我在收集位置总共有442161个文档。我必须做一些前缀搜索。我已经在(国家/地区,docType),(地区,docType),(城市,docType)和(国家/地区,地区,城市)中做了索引。我的mongo版本是2.4.9 db.location.find( { "$or": [ { "country_lc": /^unit/, "docType": "
db.location.find(
{ "$or": [
{ "country_lc": /^unit/, "docType": "country" },
{ "region_lc": /^unit/, "docType": "region" },
{ "city_lc": /^unit/, "docType": "city" }
]},
{ "country": 1, "region": 1, "city": 1, "docType" :1 }
).sort({ "country_lc" :1, "region_lc": 1, "city_lc":1 })
不管你用哪种方式摇晃它,这是一个可怕的查询,它总是会导致一个完整的集合扫描,或者至少是一个完整的索引扫描 就这一份文件而言:
{
“国家”——“统一”,
“区域”lc:“最单元”,
“城市信用证”:“至少”
}
由于$或
运算符的“排他”(排除所有内容)性质,查询不可能锚定在索引中的任何位置,因为无论您如何组织索引字段的顺序,它们都不会匹配
因此,这些方法或其他组合实际上都不会包含索引:
db.location.ensureIndex({
“国家/地区”:1,
“区域:1,
"城市(lc):1
})
db.location.ensureIndex({
“区域:1,
“城市信用证”:1,
“国家/地区”:1
})
db.location.ensureIndex({
“区域:1,
“国家/地区”:1,
"城市(lc):1
})
即使您.hint()
查询,它也不可能找到范围,这同样是由于“独占”性质:
db.location.find(
{“$or”:[
{“国家/地区”:/^unit/},
{“地区”:/^unit/},
{“城市”:/^unit/}
]}
).提示(
{国家立法会:1,地区立法会:1,城市立法会:1}
).解释
我所能想到的是,你实际上并不是指“以‘单位’开头的单词”,而是指其他的东西
这不仅仅是MongoDB的事情,这对于任何数据库引擎来说都是一件可怕的事情
你可能真的想要一个专门的“文本搜索”引擎
编辑
有些人发布了未经告知的回复,因此我认为我将实际发布建议查询的解释输出:
{
“光标”:“B光标国家/地区/城市/城市”,
“isMultiKey”:错误,
“n”:1,
“非扫描对象”:1,
“未扫描”:1,
“nscannedObjectsAllPlans”:1,
“NSCanendallPlans”:1,
“扫描者”:错误,
“indexOnly”:错误,
“NYELDS”:0,
“跳过”:0,
“毫”:0,
“指数边界”:{
“国家信用证”:[
[
{
“$minElement”:1
},
{
“$maxElement”:1
}
]
],
“地区/地方”:[
[
{
“$minElement”:1
},
{
“$maxElement”:1
}
]
],
“城市信用证”:[
[
{
“$minElement”:1
},
{
“$maxElement”:1
}
]
]
},
“服务器”:“ubuntu:27017”,
“过滤器集”:错误
}
这清楚地表明,即使选择了索引,也不可能匹配索引范围内的任何内容
关于已经发表的错误评论,这个查询解释响应来自MongoDB的2.6版本。并且在当前的夜间版本中也会被重新应用。您可以尝试在国家/地区/lc
和城市/lc
字段中创建:
{
"cursor" : "BtreeCursor country_lc_1_region_lc_1_city_lc_1",
"isMultiKey" : false,
"n" : 29,
"nscannedObjects" : 76935,
"nscanned" : 442161,
"nscannedObjectsAllPlans" : 76935,
"nscannedAllPlans" : 442161,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 79,
"nChunkSkips" : 0,
"millis" : 81531,
"indexBounds" : {
"country_lc" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"region_lc" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"city_lc" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"server" : "prashanta:27017"
}
文本索引是MongoDB 2.4中的一项新功能。添加它们是为了支持集合文档中字符串内容的文本搜索。有关性能提示,请参阅官方文档
此外,您还可以尝试将查询重写为
db.reviews.ensureIndex( { "country_lc": "text" } )
db.reviews.ensureIndex( { "region_lc": "text" } )
db.reviews.ensureIndex( { "city_lc": "text" } )
(注意:这是否等同于您的查询,取决于文档的结构。)现在我碰巧知道您运行的是2.4.9,这意味着您没有索引交叉部分,
$或
s无法使用排序索引。这个答案可能与2.6中的答案不同
您的查询存在多个问题,在MongoDB中,除了正则表达式之外,它被认为是一个“坏”查询
好的,让我们进行排序,在2.4.9中,$或
上的排序将不会正确使用索引(),这意味着您没有扫描和排序器
,但您的扫描计数是集合大小的数倍
精确地说,nscanned
是442161,因为$或
实际上是同时运行多个查询(),其结果被合并然后返回,因此即使在2.4.9中,您也可以在$或
上使用多个索引来证明这一点
我看不出您的子句正在使用什么索引,但我假设这些索引也可能不适合索引
问题是2.4.9根本无法执行$或并使用适当的索引进行排序。您必须在索引$或或排序之间进行选择,甚至只能部分覆盖查询
要解决此问题,您可以做以下几件事:
- 升级到2.6,其中
$或和排序可以使用索引
- 即使在2.6中,由于添加了
docType
字段,您也可能会遇到问题。您可以尝试在国家/地区\u lc
之后立即将其添加到索引中,但是您也可以将其添加到索引的末尾,它可以正常工作,但请记住
db.location.find(
{ "docType": {"$in": [ "country", "region", "city" ]},
"$or": [
{ "country_lc": /^unit/ },
{ "region_lc": /^unit/ },
{ "city_lc": /^unit/ },
]
},
{ "country": 1, "region": 1, "city": 1, "docType" :1 }
).sort({ "country_lc" :1, "region_lc": 1, "city_lc":1 })