Mongo 脚本在本地运行得很快,但如果我在远程实例上运行它会很慢?

Abe*_*ler 5 javascript performance mongodb mongodb-query

我有一个 mongo 脚本,用于在数据库迁移后执行一些数据清理。

当我在本地运行此脚本时,它会在大约 5 分钟内完成。当我从本地机器对远程实例运行脚本时,它需要永远(我通常在大约两个小时后杀死它)。这些数据库本质上是相同的。索引都是一样的,也许一个地方的一些记录不在另一个地方。

我正在像这样执行脚本:

本地-

mongo localDatabase script.js
Run Code Online (Sandbox Code Playgroud)

针对远程实例-

mongo removeServer/remoteDatabase -u user -p password script.js
Run Code Online (Sandbox Code Playgroud)

我曾假设,由于我将脚本传递给远程实例,它将完全在远程机器上执行,而无需在远程机器和我的本地机器之间来回传输数据(因此在表现)。

这个假设正确吗?知道为什么我看到本地/远程之间的巨大性能差异吗?有关如何修复的建议?

Nei*_*unn 4

是的,您可以使用批量操作,MongoDB 中的所有操作都是围绕单个集合设计的,但是循环一个集合并插入或更新另一个集合没有任何问题。

事实上,在 MongoDB 2.6 shell 中,这是最好的方法,并且实际的收集方法本身尝试在幕后使用“Bulk”方法,即使它们实际上每个操作只执行单个更新/插入。这就是为什么您会在 shell 中看到不同的响应。

请注意,您的服务器也需要是 MongoDB 2.6 或更高版本的实例,这就是为什么 shell 中的收集方法会在您连接到旧服务器时进行一些检测。

但基本上你的过程是:

    var bulk = db.targetcollection.initializeOrderedBulkOP();
    var counter = 0;

    db.sourcecollection.find().forEach(function(doc) {

        bulk.find({ "_id": doc._id }).updateOne(
            // update operations here
        );
        counter++;

        if ( counter % 1000 == 0 ) {
            bulk.execute();
            bulk = db.targetcollection.initializeOrderedBulkOP();
        }

    });

    if ( counter % 1000 != 0 )
        bulk.execute();
Run Code Online (Sandbox Code Playgroud)

Bulk API 本身会将您发送给它的所有操作保持“排队”,直到调用将操作发送到服务器的执行。API 本身只会将所有操作保留为“排队”,直到调用该操作为止,但实际上一次只会批量发送 1000 个条目。这里需要额外注意一点,使用模数手动限制这一点,以避免占用额外的内存。

您可以根据需要调整该数量,但请记住,确实存在 16MB 的硬性限制,因为这基本上会转换为 BSON 文档作为请求。

请参阅完整的手册页了解所有选项,包括更新插入、多重更新、插入和删除。或者甚至是无序操作,其中单个错误的顺序或失败并不重要。

另请注意,后一种情况下的写入结果将返回列表中的错误项(如果有),以及包含应用这些内容的更新插入列表等内容的响应。

结合使 shell 实例尽可能靠近服务器,减少“来回”流量将加快速度。正如我所说,无论如何 shell 都会使用这些,所以您不妨利用这些来发挥您的优势。