コンソールへ移動

Cloud Firestore のベスト プラクティス

ここで紹介するベスト プラクティスは、Cloud Firestore を使用するアプリケーションを構築する際のクイック リファレンスとしてご利用ください。

ドキュメント ID

  • ドキュメント ID に ... は使用しないでください。
  • ドキュメント ID に /(スラッシュ)は使用しないでください。
  • 次のように、単調に増加するドキュメント ID を使用しないでください。

    • Customer1Customer2Customer3、...
    • Product 1Product 2Product 3、...

    このように連続した ID を使用すると、レイテンシに影響を与えるホットスポットが生じる可能性があります。

フィールド名

  • 追加のエスケープが必要になるため、フィールド名に次の文字は使用しないでください。

    • .(ピリオド)
    • [(左角かっこ)
    • ](右角かっこ)
    • *(アスタリスク)
    • `(バッククォート)

インデックス

  • インデックスを過剰に使用しないでください。インデックスの数が多すぎると、書き込みレイテンシが増加し、インデックス エントリのストレージ コストが増加する可能性があります。

  • 読み取りレートや書き込みレートが高いアプリケーションの場合、タイムスタンプのように単調に増加する値を持つフィールドにインデックスを作成すると、レイテンシに影響を与えるホットスポットが生じる可能性があります。

インデックスの除外

ほとんどのアプリでは、インデックスを自動的に作成し、エラー メッセージのリンクでインデックスを管理できます。ただし、次のようなケースでは、単一フィールド除外を追加したほうがよい場合があります。

ケース 説明
大きな文字列フィールド

クエリには使用しない長い文字列値を保持することが多い文字列フィールドがある場合は、インデックス作成からそのフィールドを除外することでストレージの費用を削減できます。

コレクションへの書き込みレートが高く、連続した値を持つドキュメントが含まれる

コレクション内のドキュメント間で順次に増加または減少するフィールド(タイムスタンプなど)のインデックスを作成する場合は、コレクションへの最大書き込みレートは 500 回/秒です。連続した値を持つフィールドに基づいてクエリを実行することがない場合は、そのフィールドをインデックス作成から除外すれば、この制限を回避できます。

たとえば、書き込みレートが高い IoT のユースケースでは、タイムスタンプ フィールドを持つドキュメントを含むコレクションは、500 回/秒の書き込み上限に近づく可能性があります。

大規模な配列フィールドまたはマップ フィールド

大規模な配列フィールドまたはマップ フィールドの場合、ドキュメントごとに 20,000 件のインデックス エントリの上限に近づく可能性があります。大規模な配列フィールドまたはマップ フィールドに基づいてクエリを実行することがない場合は、そのフィールドをインデックス作成から除外してください。

読み取り / 書き込みオペレーション

  • ドキュメントへの書き込みを 1 秒間に複数回行わないでください。詳しくは、同一ドキュメントに対する更新をご覧ください。

  • 書き込みと削除には、単一のオペレーションではなく、バッチ オペレーションを使用します。バッチ オペレーションでは、単一オペレーションと同じオーバーヘッドで複数のオペレーションが実行されるため効率的です。

  • 可能な場合は、同期呼び出しではなく非同期呼び出しを使用します。非同期呼び出しでは、レイテンシの影響が最小限に抑えられます。たとえば、ドキュメントの検索結果とクエリの結果に従ってレスポンスをレンダリングするアプリケーションについて考えてみましょう。検索とクエリにデータの依存関係がない場合、検索が完了するまでクエリの開始を同期的に待機する必要はありません。

  • オフセットは使用しないでください。その代わりにカーソルを使用します。オフセットを使用すると、スキップされたドキュメントがアプリケーションに返されなくなりますが、内部ではスキップされたドキュメントも引き続き取得されています。スキップされたドキュメントはクエリのレイテンシに影響し、このようなドキュメントの取得に必要な読み取りオペレーションは課金対象になります。

スケールを考慮して設計する

ここでは、競合の発生を防ぐためのベスト プラクティスについて説明します。

同一ドキュメントに対する更新

同じドキュメントを 1 秒間に何度も更新しないでください。ドキュメントを頻繁に更新すぎると、アプリケーションで競合が発生します。レイテンシの増加やタイムアウト、その他のエラーなども発生します。

狭いドキュメント範囲に対する高頻度の読み取り、書き込み、削除

辞書順で近い一連のドキュメントに対して、高頻度で読み取りや書き込みを行わないでください。この問題はホットスポットといいます。次のいずれかを行うと、アプリケーションにホットスポットが生じる可能性があります。

  • 非常に高い頻度で新しいドキュメントを作成し、単調に増加する ID を割り当てる。

    Cloud Firestore では、散布アルゴリズムでドキュメント ID が割り当てられます。新しいドキュメントのドキュメント ID を自動的に割り当てている場合、書き込み時にホットスポットは生じません。

  • ドキュメント数が少ないコレクションで、新しいドキュメントを頻繁に作成する。

  • タイムスタンプのように単調に増加するフィールドを持つ新しいドキュメントを非常に高い頻度で作成する。

  • コレクション内のドキュメントを高頻度で削除する。

  • トラフィックを徐々に増やすことなく、高頻度でデータベースに書き込みを行う。

トラフィックを増やしていく

Cloud Firestore がトラフィックの増加に合わせてドキュメントを準備できるように、新しいコレクションまたは辞書順で近いドキュメントに対するトラフィックを徐々に増やしていく必要があります。新しいコレクションに対するオペレーションは、毎秒 500 回を上限とし、その後、5 分ごとにトラフィックを 50% 増やしていくことをおすすめします。この方法で読み取りトラフィックを増やした場合、90 分後には毎秒 740,000 回のオペレーションに増やすことができます。書き込みトラフィックも同様に増やすことができますが、Cloud Firestore の標準アカウントには上限があります。オペレーションがキー範囲全体に比較的均等に分散するよう注意してください。これは「500/50/5」ルールといいます。

新しいコレクションへのトラフィックの移行

アプリのトラフィックをコレクション間で移行する場合、段階的な増加は特に重要になります。この移行を簡単に処理するには、まず古いコレクションから読み取りを行い、ドキュメントが存在しない場合に新しいコレクションから読み取りを行います。ただし、新しいコレクション内で辞書的に近いドキュメントのトラフィックが急増する可能性があります。Cloud Firestore では、トラフィックの増加に合わせて新しいコレクションを効率的に準備できない可能性があります(特にドキュメントが少ない場合)。

同じコレクション内で多くのドキュメントの ID を変更した場合も、同様の問題が発生する可能性があります。

トラフィックを新しいコレクションに移行する最善の方法はデータモデルによって異なります。以下では「同時読み込み」という方法について説明します。この方法が実際のデータに対して効果的かどうかは、ご自身で判断する必要があります。また、移行中の同時操作によるコスト増も考慮する必要があります。

同時読み取り

トラフィックを新しいコレクションに移行するときに同時読み取りを行うには、まず古いコレクションから読み取りを行います。ドキュメントが見つからない場合は、新しいコレクションから読み取ります。存在しないドキュメントを高頻度で読み取るとホットスポットが生じる可能性があるため、新しいコレクションへの負荷を徐々に増やしていく必要があります。より良い方法としては、古いドキュメントを新しいコレクションにコピーしてから古いドキュメントを削除する方法があります。Cloud Firestore が新しいコレクションへのトラフィックを確実に処理できるように、同時読み取りを徐々に増やしていきます。

また、新しいコレクションへの読み取りや書き込みを徐々に増やす方法として、ユーザー ID の決定論的ハッシュを使用して、新しいドキュメントに書き込みを行うユーザーの割合をランダムに選択する方法も考えられます。この場合、ユーザー ID ハッシュの結果が関数やユーザーの行動によって偏らないようにする必要があります。

古いドキュメントから新しいコレクションにすべてのデータをコピーするバッチジョブを実行する方法もあります。ホットスポットを防ぐため、バッチジョブでは連続したドキュメント ID への書き込みを避ける必要があります。バッチジョブが終了すると、新しいコレクションからのみ読み取りが可能になります。

この方法を改善してみましょう。まず、一度に移行するユーザーを小さいバッチにまとめます。そのユーザーの移行ステータスを追跡するフィールドをユーザー ドキュメントに追加します。ユーザー ID のハッシュに基づいて、移行するユーザーのバッチを選択します。このバッチのドキュメントを移行するバッチジョブを実行し、移行の途中でユーザーの同時読み取りを行います。

ロールバックは簡単にはできません。ロールバックを行うには、移行段階が完了するまで新旧両方のエンティティに二重に書き込む必要があります。ただし、これを行うと Cloud Firestore の使用料が増加します。

不正アクセスを防止する

Cloud Firestore セキュリティ ルールを使用して、データベースに対する不正オペレーションを防止します。たとえば、ルールを使用することによって、悪意のあるユーザーがデータベース全体を繰り返しダウンロードする行為を防止できます。

詳しくは、Cloud Firestore セキュリティ ルールの使用をご覧にください。