我在MongoDB中有以下集合:
{
"_id" : ObjectId("..."),
"assetId" : "...",
"date" : ISODate("..."),
...
}
我需要做的很简单-为每个设备/资产查找最新记录。我有以下查询:
db.collection.aggregate([
{ "$match" : { "assetId" : { "$in" : [ up_to_80_ids ]} } },
{ "$group" :{ "_id" : "$assetId" , "date" : { "$last" : "$date"}}}
])
整个桌子大约20Gb。当我尝试执行此查询时,大约需要8秒钟,这毫无意义,据我指定仅应选择$ last记录。 assetId和date都已建立索引。如果我在组之前添加{$ sort:{date:1}},则不会更改任何内容。
基本上,我的查询结果不应取决于数据大小。我唯一需要的是每个设备/资产的最高记录。如果我改为执行80个单独的查询,则需要花费几毫秒的时间。
有什么办法可以使MongoDB不会遍历整个表?看起来数据库不会减少但会处理所有内容?好吧,我知道这种行为应该有一些充分的理由,但是我在文档或论坛中找不到任何内容。
更新:
最终为2.4.6找到了解释查询的正确语法:
db.runCommand( { aggregate: "collection", pipeline : [...] , explain : true })
结果:
{
“ serverPipeline”:[
{
“查询”:{
“ assetId”:{
“ $ in”:[
“ 52744d5722f8cb9b4f94d321”,
“ 52791fe322f8014b320dae41”,
“ 52740f5222f8cb9b4f94d306”,
...由于SO限制,必须删除一些
“ 52744d1722f8cb9b4f94d31d”,
“ 52744b1d22f8cb9b4f94d308”,
“ 52744ccd22f8cb9b4f94d319”
]
}
},
“投影”:{
“ assetId”:1
“日期”:1
“ _id”:0
},
“光标”:{
“ cursor”:“ BtreeCursor assetId_1 multi”,
“ isMultiKey”:false,
“ n”:960881,
“ nscannedObjects”:960881,
“ nscanned”:960894,
“ nscannedObjectsAllPlans”:960881,
“ nscannedAllPlans”:960894,
“ scanAndOrder”:否,
“ indexOnly”:false,
“ nields”:9
“ nChunkSkips”:0,
“ millis”:6264,
“ indexBounds”:{
“ assetId”:[
[
“ 52740baa22f8cb9b4f94d2e8”,
“ 52740baa22f8cb9b4f94d2e8”
],
[
“ 52740bed22f8cb9b4f94d2e9”,
“ 52740bed22f8cb9b4f94d2e9”
],
[
“ 52740c3222f8cb9b4f94d2ea”,
“ 52740c3222f8cb9b4f94d2ea”
],
....
[
“ 5297770a22f82f9bdafce322”,
“ 5297770a22f82f9bdafce322”
],
[
“ 529df5f622f82f9bdafce429”,
“ 529df5f622f82f9bdafce429”
],
[
“ 529f6a6722f89deaabbf9881”,
“ 529f6a6722f89deaabbf9881”
],
[
“ 52a6e35122f89ce6e2cf4267”,
“ 52a6e35122f89ce6e2cf4267”
]
]
},
“ allPlans”:[
{
“ cursor”:“ BtreeCursor assetId_1 multi”,
“ n”:960881,
“ nscannedObjects”:960881,
“ nscanned”:960894,
“ indexBounds”:{
“ assetId”:[
[
“ 52740baa22f8cb9b4f94d2e8”,
“ 52740baa22f8cb9b4f94d2e8”
],
[
“ 52740bed22f8cb9b4f94d2e9”,
“ 52740bed22f8cb9b4f94d2e9”
],
[
“ 52740c3222f8cb9b4f94d2ea”,
“ 52740c3222f8cb9b4f94d2ea”
],
.......
[
“ 529df5f622f82f9bdafce429”,
“ 529df5f622f82f9bdafce429”
],
[
“ 529f6a6722f89deaabbf9881”,
“ 529f6a6722f89deaabbf9881”
],
[
“ 52a6e35122f89ce6e2cf4267”,
“ 52a6e35122f89ce6e2cf4267”
]
]
}
}
],
“ oldPlan”:{
“ cursor”:“ BtreeCursor assetId_1 multi”,
“ indexBounds”:{
“ assetId”:[
[
“ 52740baa22f8cb9b4f94d2e8”,
“ 52740baa22f8cb9b4f94d2e8”
],
[
“ 52740bed22f8cb9b4f94d2e9”,
“ 52740bed22f8cb9b4f94d2e9”
],
[
“ 52740c3222f8cb9b4f94d2ea”,
“ 52740c3222f8cb9b4f94d2ea”
],
........
[
“ 529df5f622f82f9bdafce429”,
“ 529df5f622f82f9bdafce429”
],
[
“ 529f6a6722f89deaabbf9881”,
“ 529f6a6722f89deaabbf9881”
],
[
“ 52a6e35122f89ce6e2cf4267”,
“ 52a6e35122f89ce6e2cf4267”
]
]
}
},
“服务器”:“ 351bcc56-1a25-61b7-a435-c14e06887015.local:27017”
}
},
{
“ $ group”:{
“ _id”:“ $ assetId”,
“日期”:{
“ $ last”:“ $ date”
}
}
}
],
“好”:1
}
最佳答案
您的explain
输出表明在您的$match
阶段有960,881个与assetIds匹配的项目。 MongoDB使用assetId
上的索引找到所有这些对象,并通过$group
阶段将它们全部流化。这很贵。目前,MongoDB尚未对聚合管道进行很多全管道优化,因此您所写的几乎是全部。
MongoDB可以通过按assetId升序和日期降序排序,然后应用SERVER-9507中建议的优化来优化此管道,但是尚未实现。
目前,最好的做法是对每个assetId执行以下操作:
db.collection.find({assetId: THE_ID}).sort({date: -1}).limit(1)