2

1000000 を超えるドキュメントを含む mongoDB コレクションがあり、各ドキュメントを専用の情報で 1 つずつ更新したいと考えています (各ドキュメントには他のコレクションからの情報があります)。

現在、コレクションからすべてのデータを取得するカーソルを使用しており、Node.js の非同期モジュールを介して各レコードの更新を行っています。

すべてのドキュメントを取得:

inst.db.collection(association.collection, function(err, collection) {
    collection.find({}, {}, function(err, cursor) {
        cursor.toArray(function(err, items){
                 ......
        );
    });
});

各ドキュメントを更新します:

items.forEach(function(item) {
    // *** do some stuff with item, add field etc.
    tasks.push(function(nextTask) {
       inst.db.collection(association.collection, function(err, collection) {
           if (err) callback(err, null);
           collection.save(item, nextTask);
       });
    });
});

「保存」タスクを並行して呼び出す

async.parallel(tasks, function(err, results) {
    callback(err, results);
});

この種の操作をより効率的な方法で行うにはどうすればよいでしょうか? カーソルをロードするための最初の「検索」を回避する方法を意味します。すべてのドキュメントを更新する必要があることを知って、ドキュメントごとに操作を行う方法はありますか?

ご協力ありがとうございました。

4

1 に答える 1

1

あなたの問題に触発されて、問題に対するさまざまなアプローチのパフォーマンステストを行うための要点を作成しました。

以下は、ローカルホストで MongoDB を使用して小さな EC2 インスタンスで実行した結果です。テスト シナリオは、100000 要素コレクションのすべてのドキュメントに対して一意に動作することです。

  1. 108.661 秒 -- find().toArray を使用してすべてのアイテムを一度に取り込み、ドキュメントを個別の「保存」呼び出しに置き換えます。
  2. 99.645 秒 -- find().toArray を使用してすべてのアイテムを一度に取得し、個々の「更新」呼び出しでドキュメントを更新します。
  3. 74.553 秒 -- カーソル (find().each) を batchSize = 10 で反復し、個々の更新呼び出しを使用します。
  4. 58.673 秒 -- batchSize = 10000 でカーソル (find().each) を反復し、個々の更新呼び出しを使用します。
  5. 4.727 秒 -- batchSize = 10000 でカーソルを反復処理し、一度に 10000 アイテムを新しいコレクションに挿入します。

含まれていませんが、約 19 秒で実行されるサーバー側フィルターとして MapReduce を使用してテストも行いました。同様に「集計」をサーバー側のフィルターとして使用したかったのですが、コレクションに出力するオプションがまだありません。

要するに、それを回避できる場合、最速のオプションは、カーソルを介して最初のコレクションからアイテムを取得し、それらをローカルで更新して、大きなチャンクで新しいコレクションに挿入することです。その後、新しいコレクションを古いものと交換できます。

データベースをアクティブに保つ必要がある場合、最適なオプションは、batchSize が大きいカーソルを使用して、ドキュメントを適切に更新することです。「保存」呼び出しは、ドキュメント全体を置き換える必要があり、おそらく再インデックス化する必要があるため、「更新」よりも遅くなります。

于 2013-01-22T04:41:11.937 に答える