性能调优MongoDB查询/更新?

时间:2014-02-12 00:39:05

标签: performance mongodb mongodb-query

所以我有一个MongoDB实例,我试图用另一个集合中的数据更新一个集合中的数据。这两个集合是participants,包含大约180,000个文档,questions包含大约95,000个文档。

participants中的文档通常如下所示:

{
    "_id" : ObjectId("52f90b8bbab16dd8594b82b4"),
    "answers" : [
        {
            "_id" : ObjectId("52f90b8bbab16dd8594b82b9"),
            "question_id" : 2081,
            "sub_id" : null,
            "values" : [
                "Yes"
            ]
        },
        {
            "_id" : ObjectId("52f90b8bbab16dd8594b82b8"),
            "question_id" : 2082,
            "sub_id" : 123,
            "values" : [
                "Would prefer to go alone"
            ]
        },
        {
            "_id" : ObjectId("52f90b8bbab16dd8594b82b7"),
            "question_id" : 2082,
            "sub_id" : 456,
            "values" : [
                "Yes"
            ]
        }
    ],
    "created" : ISODate("2012-03-01T17:40:21Z"),
    "email" : "anonymous",
    "id" : 65,
    "survey" : ObjectId("52f41d579af1ff4221399a7b"),
    "survey_id" : 374
}

我正在使用以下查询来执行更新:

db.participants.ensureIndex({"answers.question_id": 1, "answers.sub_id": 1});
print("created index for answer arrays!")
db.questions.find().forEach(function(doc){
    db.participants.update(
        {
            "answers.question_id": doc.id,
            "answers.sub_id": doc.sub_id
        },
        {
            $set:
            {
                "answers.$.question": doc._id
            }

        },
        false,
        true
    );
});
db.participants.dropIndex({"answers.question_id": 1, "answers.sub_id": 1});

但这需要大约20分钟才能运行。我希望添加索引有助于提高性能,但它仍然很慢。考虑到我正在索引对象数组中的字段,这个索引是否正确设置?谁能看到我正在做的任何会导致缓慢的事情?关于从哪里开始寻求提高此查询性能的建议?

2 个答案:

答案 0 :(得分:1)

我认为您需要考虑实际在此做什么,以便理解为什么索引没有帮助,以及为什么这个操作需要这么长时间。

答案的第一部分是通过你在这里做的来解释的:

db.questions.find()

现在,仅此部分基本上表示您要求检索questions集合中的每个文档。因此,我们可以看到您要执行的操作正是如此,因为您希望将该内容更新到participants集合中,尤其是“问题”的文档_id。但是在这里,根据获取所有文档的定义,不会使用任何索引。

所以你正在做的是循环questions中的每个文档,然后通过更新操作询问匹配 participants记录来自“问题”的数据。这意味着你将所有95K文件“通过电线”拉回来,并通过“线路”发回你的更新操作,95K次。这不会发生在服务器上,并且您的应用程序和MongoDB之间存在网络流量。

索引本身除了改进每个participants记录的搜索之外不会做太多,这比扫描更好,你应该得到匹配。但这不是花时间的部分,而是questions的最大问题。另请注意,如果您要更新

因此,如果可以在与MongoDB服务器的网络术语尽可能接近的计算机上运行更新过程,那么这将是您最佳的性能改进。如果你想要有点大胆和/或可以检查另一个操作中的完整性,你也可以收回你的Write Concern,这将减少你的网络流量并等待对更新的响应(这是如果你把它放在“ fire and forget ”模式中。

如果您不确定概念,请参阅指南:

http://docs.mongodb.org/manual/core/write-concern/

答案 1 :(得分:0)

如果有人感兴趣,我可以在选择questions文档时使用投影,将此更新查询的运行时间从20分钟缩短到大约一分半钟。由于我仅使用_ididsub_id字段,因此我能够执行以下操作:

db.questions.find({},{_id: 1, id: 1, sub_id: 1}).forEach(function(doc){
    ....

其中性能大幅提升。希望这有助于某人!