gpt4 book ai didi

MongoDB 复合索引优化键和范围条件更新

转载 作者:可可西里 更新时间:2023-11-01 10:27:57 27 4
gpt4 key购买 nike

已阅读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'存储'first document',旧文档和新文档的字段可以不同,因此它不能是$set查询,它应该改写文档。对于下面的示例,“otherField”不应该存在,它应该是“otherField2”。

基于我对 MongoDB 文档和 this article 的理解, 我按照下面创建了索引

db.sample.createIndex({_id:1, timestamp:1})

然后我尝试使用具有以下规范的 MongoDB 3.0.4 在一个独立的实验节点上对查询进行基准测试:

  • MongoDB 3.0.4
  • 机器是空的,没有其他操作,只有mongo
  • 内存 ~30GB
  • 磁盘已剥离 RAID 0
  • 馆藏有6000万条记录
  • 平均对象大小 1001 字节
  • 索引大小 5.34 gig

当我检查日志时,许多更新查询需要超过 100 毫秒,而当我执行 mongotop 时,查询的顶部是写入查询,大约需要 1000 毫秒。它有点慢,因为执行一个查询需要很长时间。

当我执行 mongostat 时,吞吐量仅为每秒 400-500 个查询

然后我尝试使用查找查询进行查询解释(因为更新不支持解释)

  • 当我不使用投影时,它使用默认索引 {_id:1}。
  • 当我仅对 _id 和时间戳使用投影时,它使用的是 {_id:1, timestamp:1} 索引。

我的问题是:

  1. 我创建的索引是否有助于更新查询?
  2. 如果没有帮助,那么索引应该如何设置?
  3. 还有其他方法可以优化此更新查询吗?

最佳答案

  1. 有点。但不是最优的。

  2. 确实应该是这样,所以在 _id 键中对象的“元素”上建立索引:

    db.sample.createIndex({ "_id.userId": 1, "timestamp": 1 })
  3. 使用 $set运算符(operator)并停止覆盖您的文档:

    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 将“仅”更新您指定的字段。我认为您在输入问题时犯了一个错误,因为“更新”部分的语法无效。但无论如何都要使用更新运算符,因为它们通过发送单个字段或仅发送您打算更新的字段来发送较少的流量。

关于MongoDB 复合索引优化键和范围条件更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31691322/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com