多くのドキュメントをFirestoreに書き込む最も速い方法は何ですか?


回答:


26

TL; DR:Firestoreで一括データ作成を実行する最も速い方法は、個別の並列書き込み操作を実行することです。

1,000個のドキュメントをFirestoreに書き込むには、次のことが必要です。

  1. ~105.4s 順次個別書き込み操作を使用する場合
  2. ~ 2.8s (2)バッチ書き込み操作を使用する場合
  3. ~ 1.5s 並列の個別書き込み操作を使用する場合

Firestoreで多数の書き込み操作を実行するには、3つの一般的な方法があります。

  1. 個々の書き込み操作を順番に実行します。
  2. 一括書き込み操作を使用する。
  3. 個々の書き込み操作を並行して実行する。

以下では、ランダム化されたドキュメントデータの配列を使用して、それぞれを順に調査します。


個別の順次書き込み操作

これが最も簡単な解決策です。

async function testSequentialIndividualWrites(datas) {
  while (datas.length) {
    await collection.add(datas.shift());
  }
}

すべてのドキュメントを作成するまで、各ドキュメントを順番に作成します。そして、各書き込み操作が完了するのを待ってから、次の操作を開始します。

このアプローチでは1,000ドキュメントの書き込みに約105秒かかるため、スループットは1秒あたり10ドキュメントの書き込みです。


一括書き込み操作の使用

これは最も複雑なソリューションです。

async function testBatchedWrites(datas) {
  let batch = admin.firestore().batch();
  let count = 0;
  while (datas.length) {
    batch.set(collection.doc(Math.random().toString(36).substring(2, 15)), datas.shift());
    if (++count >= 500 || !datas.length) {
      await batch.commit();
      batch = admin.firestore().batch();
      count = 0;
    }
  }
}

BatchedWrite呼び出すことでオブジェクトを作成し、batch()500ドキュメントの最大容量になるまでそれを入力してから、Firestoreに書き込むことがわかります。各ドキュメントには、一意である可能性が比較的高い生成された名前を付けます(このテストには十分です)。

このアプローチでは、1,000ドキュメントの書き込みに約2.8秒かかるため、スループットは1秒あたり357ドキュメントの書き込みです。

これは、個別の順次書き込みよりもかなり高速です。実際、多くの開発者は、この方法が最速であると想定しているため、この方法を使用していますが、上記の結果がすでに示しているように、これは正しくありません。また、バッチのサイズ制限のため、コードははるかに複雑です。


並列の個別書き込み操作

Firestoreのドキュメントでは、大量のデータを追加する場合のパフォーマンスについて次のように述べています

一括データ入力には、並列化された個々の書き込みを備えたサーバークライアントライブラリを使用します。バッチ処理された書き込みは、シリアル化された書き込みよりもパフォーマンスが優れていますが、並列書き込みよりも優れていません。

これを次のコードでテストできます。

async function testParallelIndividualWrites(datas) {
  await Promise.all(datas.map((data) => collection.add(data)));
}

このコードは、add可能な限り高速に操作を開始し、Promise.all()すべてが完了するまで待機するために使用します。このアプローチでは、操作を並行して実行できます。

このアプローチでは、1,000ドキュメントの書き込みに約1.5秒かかるため、スループットは1秒あたり667ドキュメントの書き込みです。

違いは最初の2つのアプローチほど大きくありませんが、バッチ書き込みよりも1.8倍以上高速です。


いくつかのメモ:

  • このテストの完全なコードはGithubにあります。
  • テストはNode.jsで行われましたが、Admin SDKがサポートするすべてのプラットフォームで同様の結果が得られる可能性があります。
  • ただし、クライアントSDKを使用して一括挿入を実行しないでください。結果が大きく異なり、予測がはるかに困難になる可能性があります。
  • いつものように、実際のパフォーマンスはマシン、インターネット接続の帯域幅と待ち時間、およびその他の多くの要因に依存します。それらに基づいて、違いが異なる場合もありますが、順序は同じであると思います。
  • 独自のテストで外れ値がある場合、またはまったく異なる結果が見つかった場合は、下にコメントを残してください。
  • バッチ書き込みはアトミックです。したがって、ドキュメント間に依存関係があり、すべてのドキュメントを作成する必要がある場合、またはすべてのドキュメントを作成する必要がない場合は、バッチ書き込みを使用する必要があります。

1
これはとても面白いです、仕事をしてくれてありがとう!OOC、バッチ処理された書き込みの並列実行をテストしましたか?明らかに、その場合は、ドキュメントが両方のバッチに含まれないように、さらに確実にする必要があります。
robsiemb

1
並列バッチ書き込みをテストしようとしていましたが、割り当てが不足していました(これは無料のプロジェクトであり、アップグレードが面倒でした)。今日は別の日なので、試してみて、重要であれば答えを更新するかもしれません。
フランクファンPuffelen

2
@robsiemb並列バッチ書き込みでもテストしました。パフォーマンスは個々の並列書き込みと非常に似ているため、テストでは最初にそれらが関連付けられていると思います。バッチ処理された書き込みは、バックエンドで処理される性質により、より速く劣化する可能性があると思います。はるかに複雑なコードと組み合わせても、アトミック性のためだけに使用し、知覚されているが存在しないパフォーマンスの利点は使用しないことをお勧めします。
フランクファンPuffelen

@FrankvanPuffelen並列化された書き込みは、ドキュメントを「追加」するのではなく「設定」した場合にも高速になりますか?つまり、db.collection( 'cities')。add(data)ではなく、db.collection( 'cities')。doc( 'LA')。set(data)
alek6dj

呼び出しadd()は、一意のID(純粋にクライアント側)を生成し、その後にset()操作を行うだけです。したがって、結果は同じになるはずです。それがあなたが観察したものではない場合、あなたが試みたものを再現する最小限のケースで新しい質問を投稿してください。
フランクファンPuffelen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.