已阅读this doc,它声明索引可以优化更新操作。然后,我正在为我的集合添加一个索引,以优化我正在使用的更新操作。
集合中的记录具有_id对象和时间戳:
{_id: {userId: "sample"}, firstTimestamp: 123, otherField: "abc"}
我想要做的是使用以下查询进行更新:
db.userFirstTimestamp.update(
{_id: {userId: "sample"}, firstTimestamp: {$gt: 100}},
{_id: {userId: "sample"}, firstTimestamp: 100, otherField2: "efg"})
我想存储'第一份文件'基于' firstTimestamp',新旧文档的字段可以不同,因此它不能是$ set查询,它应该改写文档而不是。对于下面的示例" otherField"不应该存在,它应该是" otherField2"代替。
根据我对MongoDB doc和this article的理解,我创建了索引,如下所示
db.sample.createIndex({_id:1, timestamp:1})
然后我尝试使用MongoDB 3.0.4在一个隔离的实验节点上对查询进行基准测试,其规格如下:
当我检查日志时,许多更新查询需要超过100毫秒,而当我执行mongotop时,查询的顶部是写查询,需要大约1000毫秒。它有点慢,因为进行一次查询需要很长时间。
当我做mongostat时,吞吐量仅为每秒400-500次查询。
然后我尝试使用查询查询进行查询解释(因为更新不支持解释)
我的问题是:
答案 0 :(得分:2)
有点。但不是最佳的。
应该是这样的,所以_id
键中对象的“元素”索引:
db.sample.createIndex({ "_id.userId": 1, "timestamp": 1 })
使用$set
运算符并停止覆盖您的文档:
db.sample.update(
{
"_id.userId": "sample",
"firstTimestamp": { "$gt": 100 }
},
{
"$set": { "otherfield": "cfg" }
}
)
但实际上你的数据“应该”如下:
{
"_id": "sample",
"firstTimestamp": 200,
"otherfield2": "sam"
}
并更新如下:
db.sample.update(
{
"_id.userId": "sample",
"firstTimestamp": { "$gt": 100 }
},
{
"$set": {
"fistTimetamp": 100,
"otherfield2": "efg"
}
}
)
或者,如果你坚持认为“_id”和“firstTimestamp”以外的字段会发生很大变化,那么就这样做:
{
"_id": "sample",
"firstTimestamp": 200,
"data": {
"otherfield2": "sam"
}
}
如果您只想替换数据,请执行以下操作:
db.sample.update(
{
"_id.userId": "sample",
"firstTimestamp": { "$gt": 100 }
},
{
"$set": {
"fistTimetamp": 100,
"data": {
"overwritingField": "efg"
}
}
}
)
如果您愿意,可以将“数据”替换为整个对象,或者只更新一个密钥:
db.sample.update(
{
"_id.userId": "sample",
"firstTimestamp": { "$gt": 100 }
},
{
"$set": {
"fistTimetamp": 100,
"data.newfield": "efg"
}
}
)
在所有情况下,尝试使用运算符而不是替换整个对象,因为它通常会导致更多流量和更多负载到服务器。
但总的来说,这里有意义的是“userId”部分“应该”是索引中最能缩小结果的部分。所以它肯定会在时间戳之前进行,其中应该有更多可能的值。
复合主键很好,但请确保您实际使用它们。奇异值没有任何意义,只能分配给_id
。如果你可以在这里查询它们键的一个字段,那么你可能不需要复合对象作为主键。
更新中的_id
表示您获得了_id
的完全匹配,因此它不是具有其他键的复合字段。在这种情况下,它应该只是_id
本身的值。
另外一个“范围”是可以的,但是再次考虑你试图匹配一个文件(好吧你没有在任何地方提到“多”),所以再次询问为什么需要它然后去找一个确切的匹配或“至少”上限。
$set
将“仅”更新您指定的字段。我认为你在输入问题时犯了一个错误,因为“更新”部分的语法无效。但无论如何都要使用更新运算符,因为它们通过发送单个字段或仅打算更新的字段来减少流量。