Cloud Firestore のインデックスの種類

インデックスは、データベースのパフォーマンスにおける重要な要素です。書籍内のトピックをページ番号に対応付ける書籍の索引(インデックス)と同様に、データベースのインデックスはデータベース内のアイテムをデータベース内の場所にマッピングします。データベースにクエリを送信する際に、データベースがインデックスを使用すると、リクエストされたアイテムの場所をすばやく検索できます。

このページでは、Cloud Firestore で使用される、単一フィールド インデックス複合インデックスの 2 つのタイプのインデックスについて説明します。

すべてのクエリの背後にインデックスが存在

クエリを実行する際にインデックスが存在しないと、ほとんどのデータベースではアイテムごとにデータベースのコンテンツ全体をクロールすることになるため、データベースが大きくなるにつれて処理が大幅に遅くなります。Cloud Firestore では、すべてのクエリにインデックスを使用することで、クエリの高パフォーマンスを確保します。その結果、クエリのパフォーマンスは結果セットのサイズに依存することになり、データベース内のアイテム数には依存しません。

インデックス管理の手間を減らし、アプリ開発により注力する

Cloud Firestore には、インデックスの管理にかかる時間を短縮できる機能があります。最も基本的なクエリに必要なインデックスは、自動的に作成されます。Cloud Firestore は、アプリを使用してテストする際に、アプリで必要な追加のインデックスを識別して作成するのに役立ちます。

インデックスのタイプ

Cloud Firestore では、単一フィールド インデックスと複合インデックスという 2 つのタイプのインデックスを使用します。どちらのタイプのインデックスも、インデックス登録されるフィールドと、各フィールドのインデックス モードによって一意に定義されます。

インデックス モード

インデックスを定義するときは、インデックスを作成するフィールドごとにインデックス モードを選択します。インデックス モードには次の 3 つのオプションがあります。

インデックス モード 説明
昇順 arrow_upward フィールドでの <<===>=> の各クエリ句の使用と、そのフィールド値に基づいた結果の並べ替え(昇順)がサポートされます。
降順 arrow_downward フィールドでの <<===>=> の各クエリ句の使用と、そのフィールド値に基づいた結果の並べ替え(降順)がサポートされます。
配列の内容 フィールドでの array_contains クエリ句の使用がサポートされます。

したがって、たとえばフィールド foo の昇順モードのインデックスは、フィールド foo の降順モードのインデックスとは異なります。

単一フィールド インデックス

単一フィールド インデックスは、特定の 1 つのフィールドを含む、コレクション内のすべてのドキュメントの並べ替え済みマッピングを保持します。単一フィールド インデックスの各エントリには、ドキュメント内の特定のフィールドの値と、そのドキュメントのデータベース内での位置が記録されます。Cloud Firestore は、ドキュメント内のフィールドごとに単一フィールド インデックスを自動的に維持します。

自動インデックス

デフォルトでは、Cloud Firestore はドキュメント内のフィールドおよびマップ内のサブフィールドごとにインデックスを自動的に維持します。自動的に作成された単一フィールド インデックスでは次の設定が使用されます。

  • 配列でもなくマップでもないフィールドに対しては、2 つの単一フィールド インデックス(1 つは昇順モード、1 つは降順モード)が定義されます。

  • マップ フィールドに対しては、マップ内の配列でもなくマップでもないサブフィールドごとに、1 つの昇順インデックスと 1 つの降順インデックスが作成されます。

  • ドキュメント内の配列フィールドに対しては、配列の内容インデックスが作成、維持されます。

単一フィールド インデックス除外

単一フィールド インデックス除外を作成し、自動インデックス作成からフィールドを除外できます。インデックス除外は、データベース全体の自動インデックス設定より優先されます。除外が役立つケースについては、インデックスに関するベスト プラクティスをご覧ください。

単一フィールド インデックス除外を作成および管理する方法については、Cloud Firestore でのインデックス管理をご覧ください。

単一フィールド インデックスでサポートされているクエリの例

Cloud Firestore はこれらのインデックスを自動的に作成するため、アプリケーションでは最も基本的なデータベース クエリを迅速にサポートできます。単一フィールド インデックスを使用すると、フィールドの値と、比較演算子 <<===>=> に基づいて単純なクエリを実行できます。配列フィールドについては array_contains クエリを実行できます。

説明のために、インデックス作成の観点から cities の例について考えます。次の例では、cities コレクション内にいくつかの city ドキュメントを作成し、各ドキュメントに namestatecountrycapitalpopulationtags のフィールドを設定しています。

ウェブ
var citiesRef = db.collection("cities");

citiesRef.doc("SF").set({
    name: "San Francisco", state: "CA", country: "USA",
    capital: false, population: 860000,
    tags: ["west coast", "famous bridge"] });

citiesRef.doc("LA").set({
    name: "Los Angeles", state: "CA", country: "USA",
    capital: false, population: 3900000,
    tags: ["west coast", "great beaches", "megacity"] });

citiesRef.doc("DC").set({
    name: "Washington, D.C.", state: null, country: "USA",
    capital: true, population: 680000,
    tags: ["free museums"] });

citiesRef.doc("TOK").set({
    name: "Tokyo", state: null, country: "Japan",
    capital: true, population: 9000000,
    tags: ["megacity"] });

citiesRef.doc("BJ").set({
    name: "Beijing", state: null, country: "China",
    capital: true, population: 21500000,
    tags: ["megacity"] });

Cloud Firestore は、set オペレーションが実行されるたびに、配列以外のフィールドについては昇順の単一フィールド インデックス 1 つと降順の単一フィールド インデックス 1 つを更新し、配列フィールドについては配列の内容単一フィールド インデックス 1 つを更新します。

Cloud Firestore は、配列フィールドについては配列の内容単一インデックス 1 つ、配列以外のフィールドについては単一フィールド インデックス 2 つを更新します。次の表の各行は、単一フィールド インデックスのエントリを表しています。

コレクション インデックス登録されるフィールド
cities arrow_upward name
cities arrow_upward state
cities arrow_upward country
cities arrow_upward capital
cities arrow_upward population
cities arrow_downward name
cities arrow_downward state
cities arrow_downward country
cities arrow_downward capital
cities arrow_downward population
cities array-contains tags

自動的に作成されるこれらのインデックスを使用すると、次のようなシンプルなクエリを実行できます。

ウェブ
citiesRef.where("state", "==", "CA")
citiesRef.where("population", "<", 100000)
citiesRef.where("name", ">=", "San Francisco")

array_contains インデックスを使用すると、tags 配列フィールドをクエリできます。

ウェブ
citiesRef.where("tags", "array_contains", "mega city")

また、等式(==)に基づいて複合クエリを作成することもできます。

ウェブ
citiesRef.where("state", "==", "CO").where("name", "==", "Denver")
citiesRef.where("country", "==", "USA").where("capital", "==", false).where("state", "==", "CA").where("population", "==", 860000)

範囲比較(<<=>>=)を使用する複合クエリを実行する必要がある場合、または別のフィールドにより並べ替える必要がある場合は、そのクエリ用の複合インデックスを作成する必要があります。

複合インデックス

複合インデックスには、1 つだけではなく複数の特定のフィールドが含まれ、コレクション内のすべてのドキュメントの並べ替え済みマッピングが格納されます。複合インデックスは、各フィールドのインデックス モード(昇順、降順、配列の内容)も定義します。インデックスはインデックス モードに基づいて並べ替えられます。

Cloud Firestore では複合インデックスを使用して、単一フィールド インデックスではサポートされない複合クエリをサポートします。たとえば、次のクエリには複合インデックスが必要です。

ウェブ
citiesRef.where("country", "==", "USA").orderBy("population", "asc")
citiesRef.where("country", "==", "USA").where("population", "<", 3800000)
citiesRef.where("country", "==", "USA").where("population", ">", 690000)

これらのクエリには、以下に示す複合インデックスが必要です。これらのクエリでは country フィールドに対して等式を使用しているため、このフィールドのインデックス モードは降順と昇順のどちらでもかまいません。デフォルトでは、不等式クエリは、不等式句のフィールドに基づいて昇順を適用します。

コレクション インデックス登録されるフィールド
cities arrow_upward(または arrow_downward)country、arrow_upward population

Cloud Firestore では、可能なフィールドの組み合わせの数が多くなるため、単一フィールド インデックスの場合とは異なり、複合インデックスの自動作成は行いません。代わりに、Cloud Firestore は、アプリを作成する際に必要な複合インデックスを特定して作成できるようにします。

最初に必要なインデックスを作成せずに上記のクエリを実行しようとすると、Cloud Firestore はリンクが含まれたエラー メッセージを返します。そのリンク先にアクセスすることによって、不足しているインデックスを作成できます。この動作は、インデックスでサポートされていないクエリを試行するたびに発生します。また、コンソールまたは Firebase CLI を使用することで、複合インデックスを手動で定義して管理することもできます。インデックスの作成と管理の詳細については、インデックスの管理をご覧ください。

同じクエリを実行するけれども並べ替えが降順の場合は、population 用に降順方向の複合インデックスを追加する必要があります。

ウェブ
citiesRef.where("country", "==", "USA").orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", "<", 3800000)
         .orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", ">", 690000)
         .orderBy("population", "desc")
コレクション インデックス登録されるフィールド
cities arrow_upward country、arrow_upward population
cities arrow_upward countryarrow_downward population

array_contains クエリと他の句を組み合わせる場合も、複合インデックスを作成する必要があります。

ウェブ
citiesRef.where("tags", "array_contains", "megacity")
         .where("capital", "==", true)
コレクション インデックス登録されるフィールド
cities array-contains tags、arrow_upward(または arrow_downward)capital

インデックスと価格

インデックスはアプリケーションのストレージの費用の対象です。インデックスのストレージ サイズの計算方法の詳細については、インデックス エントリのサイズをご覧ください。

インデックス マージの活用

Cloud Firestore ではすべてのクエリにインデックスを使用しますが、クエリごとに必ず 1 つのインデックスが必要になるわけではありません。複数の等式(==)句(およびオプションで orderBy 句)が含まれるクエリに対しては、Cloud Firestore は既存のインデックスを再利用できます。Cloud Firestore では、シンプルな等式フィルタのインデックスをマージして、より大規模な等式クエリに必要な複合インデックスを作成できます。

インデックス マージを利用できる状況を特定すると、インデックスの費用を削減できます。たとえば、レストランを評価するアプリに restaurants というコレクションがある場合を考えます。

  • collections_bookmark restaurants

    • class burgerthyme

      name : "Burger Thyme"
      category : "burgers"
      city : "San Francisco"
      editors_pick : true
      star_rating : 4

ここで、このアプリは以下のようなクエリを使用するとします。categorycityeditors_pick に等式句の組み合わせを使用し、並べ替えは常に star_rating の昇順です。

ウェブ
db.collection("restaurants").where("category", "==", "burgers")
                            .orderBy("star_rating")

db.collection("restaurants").where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==" "San Francisco")
                            .where("editors_pick", "==", true )
                            .orderBy("star_rating")

それぞれのクエリに対してインデックスを作成するという方法が考えられます。

コレクション インデックス登録されるフィールド
restaurants arrow_upward category、arrow_upward star_rating
restaurants arrow_upward city、arrow_upward star_rating
restaurants arrow_upward category、arrow_upward city、arrow_upward star_rating
restaurants arrow_upward category、arrow_upward city、arrow_upward editors_pick、arrow_upward star_rating

より適切なソリューションとして、等式句のインデックスをマージする Cloud Firestore の機能を利用することにより、インデックスの数を減らすことができます。

コレクション インデックス登録されるフィールド
restaurants arrow_upward category、arrow_upward star_rating
restaurants arrow_upward city、arrow_upward star_rating
restaurants arrow_upward editors_pick、arrow_upward star_rating

このインデックス セットはサイズが小さくなっただけでなく、次のような追加のクエリもサポートします。

ウェブ
db.collection("restaurants").where("editors_pick", "==", true)
                            .orderBy("star_rating")

インデックスの制限

インデックスには以下の制限が適用されます。すべての割り当てと制限の詳細については、割り当てと制限をご覧ください。

制限 詳細
ドキュメントの複合インデックス エントリの最大合計サイズ 2 MiB
データベース 1 つあたりの複合インデックスの最大数 200
データベース 1 つあたりの単一フィールド インデックス除外の最大数 200

ドキュメントごとのインデックス エントリの最大数

20,000

インデックス エントリの数は、ドキュメントに関する次の数の合計です。

  • 単一フィールド インデックス エントリ数
  • 複合インデックス エントリ数

Cloud Firestore は各フィールドに対して、2 つの単一フィールド インデックス エントリ(昇順インデックスのエントリ 1 つ、降順インデックスのエントリ 1 つ)を自動的に作成します。

インデックス登録されるフィールド値の最大サイズ

1,500 バイト

1,500 バイトを超えるフィールド値は切り捨てられます。切り捨てられたフィールド値が含まれるクエリからは、整合性のない結果が返されることがあります。

インデックスに関するベスト プラクティス

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

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

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

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

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

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

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

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

フィードバックを送信...

ご不明な点がありましたら、Google のサポートページをご覧ください。