【问题标题】:How to improve MongoDB insert performance如何提高 MongoDB 插入性能
【发布时间】:2015-07-08 16:21:10
【问题描述】:

结果:

如果您正在对容错的数据集进行操作,或者执行一次可以验证的过程,则将 WriteAcknowledge 更改为 Unacknowledged 会有所帮助。

另外,批量操作默认是 IsOrdered 的,我没有意识到这一点。将此设置为 False 实际上会使操作批量执行,否则它将作为一个更新线程运行。


MongoDB 3.0 / WiredTiger / C# 驱动程序

我有一个包含 147,000,000 个文档的集合,其中我每秒(希望)大约执行一次更新。 3000 份文件。

这是一个更新示例:

"query" : {
    "_id" : BinData(0,"UKnZwG54kOpT4q9CVWbf4zvdU223lrE5w/uIzXZcObQiAAAA")
},
"updateobj" : {
    "$set" : {
        "b" : BinData(0,"D8u1Sk/fDES4IkipZzme7j2qJ4oWjlT3hvLiAilcIhU="),
        "s" : true
    }
}

这是一个典型的更新,我的要求是以每秒 3000 个的速度插入。

不幸的是,这些耗时是原来的两倍,例如,上次更新是针对 1723 个文档,耗时 1061 毫秒。

集合只有 _id 上的索引,没有其他索引,集合的平均文档大小为 244 字节,不封顶。

服务器有 64GB 内存,12 个线程。插入性能在较小的集合大小(例如大约 5000 万个)下非常出色,但在大约 8000 万个之后真正开始下降。

可能是因为整个集合没有放在内存中吗?数据库由 RAID0 SSD 支持,因此 IO 性能不应该成为瓶颈,如果是的话,它应该在一开始就表明这一点?

希望得到一些指导,因为我相信 MongoDB 可以满足我与使用它的某些应用程序相比相当微薄的要求。数据库的读取率并不高,因此分片不会改善问题,尽管我可能错了.

不管怎样,目前的插入率都不够好。

更新:这里只是查询的 explain()...

"queryPlanner" : {
    "plannerVersion" : 1,
    "namespace" : "Collection",
    "indexFilterSet" : false,
    "parsedQuery" : {
        "_id" : {
            "$eq" : { "$binary" : "SxHHwTMEaOmSc9dD4ng/7ILty0Zu0qX38V81osVqWkAAAAAA", "$type" : "00" }
        }
    },
    "winningPlan" : {
        "stage" : "IDHACK"
    },
    "rejectedPlans" : []
},
"executionStats" : {
    "executionSuccess" : true,
    "nReturned" : 1,
    "executionTimeMillis" : 1,
    "totalKeysExamined" : 1,
    "totalDocsExamined" : 1,
    "executionStages" : {
        "stage" : "IDHACK",
        "nReturned" : 1,
        "executionTimeMillisEstimate" : 0,
        "works" : 2,
        "advanced" : 1,
        "needTime" : 0,
        "needFetch" : 0,
        "saveState" : 0,
        "restoreState" : 0,
        "isEOF" : 1,
        "invalidates" : 0,
        "keysExamined" : 1,
        "docsExamined" : 1
    },
    "allPlansExecution" : []
},

它自己的查询非常快,更新操作大约需要 25 毫秒,它们正在使用 BulkWriter 推送到 Mongo:await m_Collection.BulkWriteAsync(updates);

【问题讨论】:

    标签: c# performance mongodb mongodb-.net-driver


    【解决方案1】:

    您可以尝试修改Write concern levels。 显然这是有风险的,因为你无法捕捉到任何写入错误,但至少你应该仍然能够捕捉到网络错误。 由于 MongoDB 将批量插入操作分组在 groups of 1000 中,这应该加快进程。

    W默认为1:

    当你将其更改为 0 时:

    如果您不关心元素的顺序,调用无序批量操作可以获得一些速度

    await m_Collection.BulkWriteAsync(updates, new BulkWriteOptions() { IsOrdered = false });
    

    使用无序操作列表,MongoDB 可以并行执行 在列表中以任意顺序写入操作。 Link

    【讨论】:

    • 感谢您的输入,您突出显示了我认为默认设置的两项!我查看了 WriteConcern 并阅读了默认为第二种类型的文档。我当然会做出这个改变,我对内存中的数据感到满意,因为它是容错的。至于 IsOrdered,我认为它总是错误的并且必须设置为 True?很大的启示,因为我希望我的插入并行,这就是我使用 BulkWrite 的原因!我会报告我的发现,非常感谢。
    • 查看ILSpy中的BulkWriteOptions,你是对的,IsOrdered标志默认为true。这非常不直观,但对了解很有帮助。
    • 请让我们了解编辑问题的每秒插入次数的增加。
    • 不幸的是,这并没有提高性能,WriteConcern 设置为 Unacknowledged,Updates 设置为 IsOrdered = false。我开始认为嵌套文档可能会减慢该过程,但插入会减慢很多,因为大约有。每个父文档中有 30 个嵌套文档,以哈希作为索引,这将杀死索引器在每个“逻辑”文档中插入 30 次。
    • 我的测试没有得出正确的结果。将 WriteConcern Unacknowledged 和 IsOrdered 设置为 false 从头开始​​重新运行导入能够保持大约。每秒 35k 的插入速率以及大约 35k 的插入速率。每秒 11k 更新速率。非常棒的结果,谢谢。
    【解决方案2】:

    "数据库没有很大的读取率所以Sharding 不会改善问题,虽然也许我错了。”

    更新涉及读取。也就是发现被遗弃的 _id ——所以如果没有帮助,分片可能会有所帮助

    【讨论】:

      【解决方案3】:

      这里的标记答案很好。我想添加一个额外的代码来帮助其他使用InsertMany 而不是BulkWriteAsync 的人更快地利用IsOrdered = false

          m_Collection.InsertMany(listOfDocument, new InsertManyOptions() { IsOrdered = false });
      

      【讨论】:

        【解决方案4】:

        我们改用 Cassandra,因为 Mongo 不能很好地扩展。如果你说在 80M 之后你看到了性能下降,很容易它与内存有关。 我更擅长 SQL DB,但我不会说 25 毫秒的非关键字段更新令人印象深刻。我怀疑类似的更新在 Oracle、MySql 上会表现得更好......

        【讨论】:

        • 感谢您的输入,我已经看到 Mongo 实例处理了数亿个键而没有任何问题,所以我确定是我做错了什么。 Mongo 过去在这种工作负载上表现出色,现在它正在扩大我遇到的问题我确信我会找到解决方案。
        猜你喜欢
        • 2021-08-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-05
        • 2021-08-01
        • 1970-01-01
        相关资源
        最近更新 更多