インデックスは、データベースのパフォーマンスにおける重要な要素です。本のトピックをページ番号にマップする本のインデックスと同様に、データベース インデックスは、データベース内の項目をデータベース内の位置にマップします。データベースにクエリを送信すると、データベースはインデックスを使用して、要求したアイテムの場所をすばやく検索できます。
このページでは、Cloud Firestore が使用する 2 種類のインデックス、単一フィールド インデックスと複合インデックスについて説明します。
すべてのクエリの背後にあるインデックス
クエリのインデックスが存在しない場合、ほとんどのデータベースはアイテムごとにコンテンツをクロールします。これは、データベースが大きくなるにつれてさらに遅くなる遅いプロセスです。 Cloud Firestore は、すべてのクエリにインデックスを使用することで、高いクエリ パフォーマンスを保証します。その結果、クエリのパフォーマンスは、データベース内のアイテムの数ではなく、結果セットのサイズに依存します。
インデックス管理が減り、アプリ開発が増える
Cloud Firestore には、インデックスの管理に費やす時間を短縮する機能が含まれています。最も基本的なクエリに必要なインデックスは、自動的に作成されます。アプリを使用してテストするときに、Cloud Firestore は、アプリに必要な追加のインデックスを特定して作成するのに役立ちます。
インデックスの種類
Cloud Firestore は、単一フィールドと複合の 2 種類のインデックスを使用します。インデックスが作成されるフィールドの数に加えて、単一フィールド インデックスと複合インデックスでは、それらの管理方法が異なります。
単一フィールド インデックス
単一フィールド インデックスは、特定のフィールドを含むコレクション内のすべてのドキュメントの並べ替えられたマッピングを格納します。単一フィールド インデックスの各エントリには、特定のフィールドに対するドキュメントの値と、データベース内のドキュメントの場所が記録されます。 Cloud Firestore はこれらのインデックスを使用して、多くの基本的なクエリを実行します。データベースの自動インデックス作成設定とインデックス除外を構成することにより、単一フィールド インデックスを管理します。
自動索引付け
デフォルトでは、Cloud Firestore はドキュメント内の各フィールドとマップ内の各サブフィールドの単一フィールド インデックスを自動的に維持します。 Cloud Firestore は、単一フィールド インデックスに次のデフォルト設定を使用します。
非配列および非マップ フィールドごとに、Cloud Firestore は 2 つのコレクション スコープの単一フィールド インデックスを定義します。1 つは昇順モードで、もう 1 つは降順モードです。
マップ フィールドごとに、Cloud Firestore は、マップ内の非配列および非マップ サブフィールドごとに、1 つのコレクション スコープの昇順インデックスと 1 つの降順インデックスを作成します。
ドキュメント内の配列フィールドごとに、Cloud Firestore はコレクション スコープの配列を含むインデックスを作成して維持します。
コレクション グループ スコープの単一フィールド インデックスは、既定では保持されません。
単一フィールド インデックスの免除
単一フィールド インデックス除外を作成することで、自動インデックス設定からフィールドを除外できます。インデックス作成の除外は、データベース全体の自動インデックス設定をオーバーライドします。除外を使用すると、自動インデックス設定で無効にする単一フィールド インデックスを有効にするか、自動インデックス設定で有効にする単一フィールド インデックスを無効にすることができます。除外が役立つ場合については、インデックス作成のベスト プラクティスを参照してください。
マップ フィールドの単一フィールド インデックス除外を作成すると、マップのサブフィールドはそれらの設定を継承します。ただし、特定のサブフィールドに対して単一フィールド インデックスの除外を定義することはできます。サブフィールドの除外を削除すると、サブフィールドは親の除外設定が存在する場合はそれを継承し、親除外が存在しない場合はデータベース全体の設定を継承します。
単一フィールド インデックスの除外を作成および管理するには、Cloud Firestore でインデックスを管理する を参照してください。
複合インデックス
複合インデックスは、インデックス付けするフィールドの順序付きリストに基づいて、コレクション内のすべてのドキュメントの並べ替えられたマッピングを格納します。
Cloud Firestore は複合インデックスを使用して、単一フィールド インデックスではまだサポートされていないクエリをサポートします。
Cloud Firestore は、考えられるフィールドの組み合わせが多数あるため、単一フィールド インデックスの場合のように複合インデックスを自動的に作成しません。代わりに、Cloud Firestore は、アプリを構築する際に必要な複合インデックスを特定して作成するのに役立ちます。
最初に必要なインデックスを作成せずに上記のクエリを実行しようとすると、Cloud Firestore は、不足しているインデックスを作成するためのリンクを含むエラー メッセージを返します。これは、インデックスでサポートされていないクエリを試行するたびに発生します。コンソールまたはFirebase CLIを使用して、複合インデックスを手動で定義および管理することもできます。複合インデックスの作成と管理の詳細については、「インデックスの管理」を参照してください。
インデックス モードとクエリ スコープ
単一フィールド インデックスと複合インデックスの構成は異なりますが、どちらもインデックス モードとインデックスのクエリ スコープを構成する必要があります。
索引モード
インデックスを定義するときは、インデックス付きフィールドごとにインデックス モードを選択します。各フィールドのインデックス モードは、そのフィールドで特定のクエリ句をサポートします。次のインデックス モードから選択できます。
インデックスモード | 説明 |
---|---|
昇順 | フィールドで< 、 <= 、 == 、 >= 、 > 、 != 、 in 、およびnot-in クエリ句をサポートし、このフィールド値に基づく昇順での結果の並べ替えをサポートします。 |
降順 | フィールドで< 、 <= 、 == 、 >= 、 > 、 != 、 in 、およびnot-in クエリ句をサポートし、このフィールド値に基づく降順での結果の並べ替えをサポートします。 |
配列の内容 | フィールドでarray-contains およびarray-contains-any クエリ句をサポートします。 |
クエリのスコープ
各インデックスは、コレクションまたはコレクション グループのいずれかにスコープされます。これは、インデックスのクエリ スコープとして知られています。
- コレクションの範囲
- Cloud Firestore は、デフォルトでコレクション スコープのインデックスを作成します。これらのインデックスは、単一のコレクションから結果を返すクエリをサポートしています。
- コレクション グループのスコープ
- コレクション グループには、同じコレクション ID を持つすべてのコレクションが含まれます。コレクション グループからフィルター処理または順序付けされた結果を返すコレクション グループ クエリを実行するには、コレクション グループ スコープで対応するインデックスを作成する必要があります。
デフォルトの順序と__name__
フィールド
各フィールドに指定されたインデックス モード (昇順または降順) によるドキュメントの並べ替えに加えて、インデックスは各ドキュメントの__name__
フィールドによる最終的な並べ替えを適用します。 __name__
フィールドの値は、完全なドキュメント パスに設定されます。これは、同じフィールド値を持つ結果セット内のドキュメントがドキュメント パスでソートされることを意味します。
デフォルトでは、 __name__
フィールドは、インデックス定義で最後にソートされたフィールドと同じ方向にソートされます。例えば:
コレクション | 索引付けされたフィールド | クエリ範囲 |
---|---|---|
都市 | __name__ | 名前、 コレクション |
都市 | __name__ | 状態、 コレクション |
都市 | __name__ | 国、 人口、 コレクション |
デフォルト以外の__name__
方向で結果をソートするには、そのインデックスを作成する必要があります。
索引付けの例
単一フィールド インデックスを自動的に作成することで、Cloud Firestore はアプリケーションが最も基本的なデータベース クエリを迅速にサポートできるようにします。単一フィールド インデックスを使用すると、フィールド値とコンパレータ<
、 <=
、 ==
、 >=
、 >
、およびin
基づいて簡単なクエリを実行できます。配列フィールドの場合、 array-contains
およびarray-contains-any
クエリを実行できます。
説明のために、インデックス作成の観点から次の例を調べます。次のスニペットは、 cities
コレクションにいくつかのcity
ドキュメントを作成し、各ドキュメントのname
、 state
、 country
、 capital
、 population
、およびtags
フィールドを設定します。
ウェブ
var citiesRef = db.collection("cities"); citiesRef.doc("SF").set({ name: "San Francisco", state: "CA", country: "USA", capital: false, population: 860000, regions: ["west_coast", "norcal"] }); citiesRef.doc("LA").set({ name: "Los Angeles", state: "CA", country: "USA", capital: false, population: 3900000, regions: ["west_coast", "socal"] }); citiesRef.doc("DC").set({ name: "Washington, D.C.", state: null, country: "USA", capital: true, population: 680000, regions: ["east_coast"] }); citiesRef.doc("TOK").set({ name: "Tokyo", state: null, country: "Japan", capital: true, population: 9000000, regions: ["kanto", "honshu"] }); citiesRef.doc("BJ").set({ name: "Beijing", state: null, country: "China", capital: true, population: 21500000, regions: ["jingjinji", "hebei"] });
デフォルトの自動インデックス設定を前提として、Cloud Firestore は、配列以外のフィールドごとに 1 つの昇順の単一フィールド インデックス、非配列フィールドごとに 1 つの降順の単一フィールド インデックス、および配列フィールドの 1 つの配列を含む単一フィールド インデックスを更新します。次の表の各行は、単一フィールド インデックスのエントリを表します。
コレクション | 索引付けされたフィールド | クエリ範囲 |
---|---|---|
都市 | 名前 | コレクション |
都市 | 状態 | コレクション |
都市 | 国 | コレクション |
都市 | キャピタル | コレクション |
都市 | 人口 | コレクション |
都市 | 名前 | コレクション |
都市 | 状態 | コレクション |
都市 | 国 | コレクション |
都市 | キャピタル | コレクション |
都市 | 人口 | コレクション |
都市 | array-contains 領域 | コレクション |
単一フィールド インデックスでサポートされるクエリ
これらの自動作成された単一フィールド インデックスを使用して、次のような単純なクエリを実行できます。
ウェブ
const stateQuery = citiesRef.where("state", "==", "CA"); const populationQuery = citiesRef.where("population", "<", 100000); const nameQuery = citiesRef.where("name", ">=", "San Francisco");
in
および複合等価 ( ==
) クエリを作成することもできます。
ウェブ
citiesRef.where('country', 'in', ["USA", "Japan", "China"]) // Compound equality queries citiesRef.where("state", "==", "CO").where("name", "==", "Denver") citiesRef.where("country", "==", "USA") .where("capital", "==", false) .where("state", "==", "CA") .where("population", "==", 860000)
範囲比較 ( <
、 <=
、 >
、または>=
) を使用する複合クエリを実行する必要がある場合、または別のフィールドで並べ替える必要がある場合は、そのクエリの複合インデックスを作成する必要があります。
array-contains
インデックスを使用すると、 regions
配列フィールドを照会できます。
ウェブ
citiesRef.where("regions", "array-contains", "west_coast") // array-contains-any and array-contains use the same indexes citiesRef.where("regions", "array-contains-any", ["west_coast", "east_coast"])
複合インデックスでサポートされるクエリ
Cloud Firestore は複合インデックスを使用して、単一フィールド インデックスではまだサポートされていない複合クエリをサポートします。たとえば、次のクエリには複合インデックスが必要です。
ウェブ
citiesRef.where("country", "==", "USA").orderBy("population", "asc") citiesRef.where("country", "==", "USA").where("population", "<", 3800000) citiesRef.where("country", "==", "USA").where("population", ">", 690000) // in and == clauses use the same index citiesRef.where("country", "in", ["USA", "Japan", "China"]) .where("population", ">", 690000)
これらのクエリには、以下の複合インデックスが必要です。クエリではcountry
フィールドに等式 ( ==
またはin
) が使用されるため、このフィールドには昇順または降順のインデックス モードを使用できます。デフォルトでは、不等式句は、不等式句のフィールドに基づいて昇順のソート順を適用します。
コレクション | 索引付けされたフィールド | クエリ範囲 |
---|---|---|
都市 | (または ) 国、 人口 | コレクション |
同じクエリを降順で実行するには、 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") citiesRef.where("country", "in", ["USA", "Japan", "China"]) .where("population", ">", 690000) .orderBy("population", "desc")
コレクション | 索引付けされたフィールド | クエリ範囲 |
---|---|---|
都市 | 国、 人口 | コレクション |
都市 | 国, 人口 | コレクション |
また、 array-contains
またはarray-contains-any
クエリを追加の句と組み合わせるには、複合インデックスを作成する必要があります。
ウェブ
citiesRef.where("regions", "array-contains", "east_coast") .where("capital", "==", true) // array-contains-any and array-contains use the same index citiesRef.where("regions", "array-contains-any", ["west_coast", "east_coast"]) .where("capital", "==", true)
コレクション | 索引付けされたフィールド | クエリ範囲 |
---|---|---|
都市 | array-containsタグ、 | (または ) 大文字コレクション |
コレクション グループ インデックスでサポートされるクエリ
コレクション グループ スコープのインデックスを示すために、いくつかのcity
ドキュメントにlandmarks
サブコレクションを追加することを想像してください。
ウェブ
var citiesRef = db.collection("cities"); citiesRef.doc("SF").collection("landmarks").doc().set({ name: "Golden Gate Bridge", category : "bridge" }); citiesRef.doc("SF").collection("landmarks").doc().set({ name: "Golden Gate Park", category : "park" }); citiesRef.doc("DC").collection("landmarks").doc().set({ name: "National Gallery of Art", category : "museum" }); citiesRef.doc("DC").collection("landmarks").doc().set({ name: "National Mall", category : "park" });
コレクション スコープで次の単一フィールド インデックスを使用すると、 category
フィールドに基づいて単一都市のlandmarks
コレクションをクエリできます。
コレクション | 索引付けされたフィールド | クエリ範囲 |
---|---|---|
ランドマーク | (または ) カテゴリ | コレクション |
ウェブ
citiesRef.doc("SF").collection("landmarks").where("category", "==", "park") citiesRef.doc("SF").collection("landmarks").where("category", "in", ["park", "museum"])
ここで、すべての都市のランドマークをクエリすることに関心があるとします。すべてのlandmarks
コレクションで構成されるコレクション グループに対してこのクエリを実行するには、コレクション グループ スコープでlandmarks
単一フィールド インデックスを有効にする必要があります。
コレクション | 索引付けされたフィールド | クエリ範囲 |
---|---|---|
ランドマーク | (または ) カテゴリ | コレクショングループ |
このインデックスを有効にすると、 landmarks
コレクション グループに対してクエリを実行できます。
ウェブ
var landmarksGroupRef = db.collectionGroup("landmarks"); landmarksGroupRef.where("category", "==", "park") landmarksGroupRef.where("category", "in", ["park", "museum"])
フィルター処理または順序付けされた結果を返すコレクション グループ クエリを実行するには、対応する単一フィールドまたは複合インデックスをコレクション グループ スコープで有効にする必要があります。ただし、結果のフィルター処理や順序付けを行わないコレクション グループ クエリには、追加のインデックス定義は必要ありません。
たとえば、追加のインデックスを有効にせずに、次のコレクション グループ クエリを実行できます。
ウェブ
db.collectionGroup("landmarks").get()
索引項目
プロジェクトの構成済みインデックスとドキュメントの構造によって、ドキュメントのインデックス エントリの数が決まります。インデックス エントリは、インデックス エントリ数の制限にカウントされます。
次の例は、ドキュメントのインデックス エントリを示しています。
書類
/cities/SF
city_name : "San Francisco"
temperatures : {summer: 67, winter: 55}
neighborhoods : ["Mission", "Downtown", "Marina"]
単一フィールド インデックス
- 都市名 ASC
- 都市名 DESC
- 温度.夏のASC
- 温度.夏 DESC
- 温度.冬の ASC
- 気温.冬 DESC
- 近隣配列の内容 (ASC および DESC)
複合インデックス
- city_name ASC、近隣 ARRAY
- city_name DESC、近隣 ARRAY
索引項目
このインデックス設定により、ドキュメントの次の 18 のインデックス エントリが作成されます。
索引 | インデックス付きデータ |
---|---|
単一フィールド インデックス エントリ | |
都市名 ASC | city_name: "サンフランシスコ" |
都市名 DESC | city_name: "サンフランシスコ" |
温度.夏のASC | 温度.夏: 67 |
温度.夏 DESC | 温度.夏: 67 |
温度.冬の ASC | 温度.冬: 55 |
気温.冬 DESC | 温度.冬: 55 |
近所の配列にはASCが含まれています | 近所:「ミッション」 |
近所の配列にはDESCが含まれています | 近所:「ミッション」 |
近所の配列にはASCが含まれています | 近所:「ダウンタウン」 |
近所の配列にはDESCが含まれています | 近所:「ダウンタウン」 |
近所の配列にはASCが含まれています | 近所:「マリーナ」 |
近所の配列にはDESCが含まれています | 近所:「マリーナ」 |
複合インデックス エントリ | |
city_name ASC、近隣 ARRAY | city_name: 「サンフランシスコ」、neighbords: 「ミッション」 |
city_name ASC、近隣 ARRAY | city_name: 「サンフランシスコ」、neighborhoods: 「ダウンタウン」 |
city_name ASC、近隣 ARRAY | city_name: 「サンフランシスコ」、neighbords: 「マリーナ」 |
city_name DESC、近隣 ARRAY | city_name: 「サンフランシスコ」、neighbords: 「ミッション」 |
city_name DESC、近隣 ARRAY | city_name: 「サンフランシスコ」、neighborhoods: 「ダウンタウン」 |
city_name DESC、近隣 ARRAY | city_name: 「サンフランシスコ」、neighbords: 「マリーナ」 |
インデックスと価格
インデックスは、アプリケーションのストレージ コストに影響します。インデックスのストレージ サイズの計算方法の詳細については、「インデックス エントリのサイズ」を参照してください。
インデックスのマージを利用する
Cloud Firestore はすべてのクエリにインデックスを使用しますが、必ずしもクエリごとに 1 つのインデックスを必要とするわけではありません。複数の等価 ( ==
) 句と、オプションでorderBy
句を含むクエリの場合、Cloud Firestore は既存のインデックスを再利用できます。 Cloud Firestore は、単純な等値フィルタのインデックスをマージして、より大きな等値クエリに必要な複合インデックスを構築できます。
インデックスのマージを利用できる状況を特定することで、インデックス作成のコストを削減できます。たとえば、レストラン評価アプリのrestaurants
コレクションを想像してみてください。
バーガータイム
name : "Burger Thyme"
category : "burgers"
city : "San Francisco"
editors_pick : true
star_rating : 4
ここで、このアプリが以下のようなクエリを使用しているとします。このアプリは、常にstar_rating
の昇順でソートしながら、 category
、 city
、 editors_pick
の等式句の組み合わせを使用していることに注意してください。
ウェブ
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")
クエリごとにインデックスを作成できます。
コレクション | 索引付けされたフィールド | クエリ範囲 |
---|---|---|
レストラン | カテゴリ、 star_rating | コレクション |
レストラン | 都市、 star_rating | コレクション |
レストラン | カテゴリ、 都市、 star_rating | コレクション |
レストラン | カテゴリ、 都市、 editors_pick、 star_rating | コレクション |
より良い解決策として、等式句のインデックスをマージする Cloud Firestore の機能を利用して、インデックスの数を減らすことができます。
コレクション | 索引付けされたフィールド | クエリ範囲 |
---|---|---|
レストラン | カテゴリ、 star_rating | コレクション |
レストラン | 都市、 star_rating | コレクション |
レストラン | editors_pick, star_rating | コレクション |
この一連のインデックスが小さいだけでなく、追加のクエリもサポートしています。
ウェブ
db.collection("restaurants").where("editors_pick", "==", true) .orderBy("star_rating")
インデックス作成の制限
インデックスには次の制限が適用されます。すべてのクォータと制限については、「クォータと制限」を参照してください。
リミット | 詳細 |
---|---|
データベースの複合インデックスの最大数 | 200 サポートに連絡して、この制限の引き上げをリクエストできます。 |
データベースの単一フィールド構成の最大数 | 200 合計 200 のフィールド レベルの構成が許可されます。 1 つのフィールド構成に、同じフィールドの複数の構成を含めることができます。たとえば、単一フィールドのインデックス作成免除と同じフィールドの TTL ポリシーは、制限に対して 1 つのフィールド構成としてカウントされます。 |
各ドキュメントのインデックス エントリの最大数 | 40,000 インデックス エントリの数は、ドキュメントの次の合計です。
Cloud Firestore がドキュメントと一連のインデックスをインデックス エントリに変換する方法については、こちらのインデックス エントリ数の例をご覧ください。 |
複合インデックス内のフィールドの最大数 | 100 |
インデックス エントリの最大サイズ | 7.5KiB Cloud Firestore がインデックス エントリのサイズを計算する方法については、インデックスエントリのサイズをご覧ください。 |
ドキュメントのインデックス エントリのサイズの最大合計 | 8 MiB 合計サイズは、ドキュメントの次の合計です。 |
インデックス付きフィールド値の最大サイズ | 1500バイト 1500 バイトを超えるフィールド値は切り捨てられます。切り捨てられたフィールド値を含むクエリは、一貫性のない結果を返す場合があります。 |
インデックス作成のベスト プラクティス
ほとんどのアプリでは、自動インデックス作成とエラー メッセージ リンクを使用してインデックスを管理できます。ただし、次の場合は、単一フィールドの除外を追加することをお勧めします。
場合 | 説明 |
---|---|
大きな文字列フィールド | クエリに使用しない長い文字列値を保持することが多い文字列フィールドがある場合は、そのフィールドをインデックス作成から除外することで、ストレージ コストを削減できます。 |
連続した値を持つドキュメントを含むコレクションへの高い書き込み率 | タイムスタンプのように、コレクション内のドキュメント間で順次増加または減少するフィールドにインデックスを付ける場合、コレクションへの最大書き込み速度は 1 秒あたり 500 書き込みです。連続した値を持つフィールドに基づいてクエリを実行しない場合は、フィールドをインデックス作成から除外して、この制限を回避できます。 たとえば、書き込み率が高い IoT ユースケースでは、タイムスタンプ フィールドを持つドキュメントを含むコレクションが、1 秒あたり 500 回の書き込み制限に近づく可能性があります。 |
TTL フィールド | TTL (time-to-live) ポリシーを使用する場合、TTL フィールドはタイムスタンプでなければならないことに注意してください。 TTL フィールドのインデックス作成はデフォルトで有効になっており、トラフィック レートが高くなるとパフォーマンスに影響を与える可能性があります。ベスト プラクティスとして、TTL フィールドに単一フィールドの除外を追加します。 |
大きな配列またはマップ フィールド | 大きな配列またはマップ フィールドは、ドキュメントあたり 40,000 のインデックス エントリの制限に近づく可能性があります。大規模な配列またはマップ フィールドに基づいてクエリを実行していない場合は、インデックス作成から除外する必要があります。 |