Enterprise エディションのインデックスの概要

インデックス登録の動作は、データベースのエディションによって異なります。このページでは、Firestore Enterprise エディションのインデックス作成について説明します。Firestore Standard エディションについては、Firestore Standard エディションのインデックスの概要をご覧ください。

このセクションでは、Firestore Enterprise エディションのインデックス作成について説明します。Firestore Enterprise エディションでは、デフォルトでインデックスが作成されません。コストを削減し、データベースのパフォーマンスを向上させるには、最もよく使用されるクエリのインデックスを作成します。

インデックスは、データベースのパフォーマンスに大きな影響を与えます。クエリにインデックスが設定されている場合、スキャンする必要があるデータ量を減らし、結果の並べ替えに必要な作業を減らすことで、データベースから効率的に結果を返すことができます。ただし、インデックス エントリはストレージ コストと、インデックス付きフィールドに対する書き込みオペレーション中に実行される作業量を増やします。

インデックスの定義と構造

インデックスは次の要素で構成されます。

  • コレクション ID
  • 指定されたコレクション内のフィールドのリスト
  • 各フィールドのインデックス モード(昇順、降順、配列の内容)

インデックスでは、スパースまたは一意のオプションを有効にすることもできます。

インデックスの順序

インデックスは、各フィールドの順序と並べ替えの方向によって一意に定義されます。たとえば、次のインデックスは 2 つの異なるインデックスであり、互換性はありません。

コレクション フィールド
cities country(昇順)、population(降順)
cities population(降順)、country(昇順)

クエリをサポートするインデックスを作成する場合は、クエリと同じ順序でフィールドを含めます。

インデックス密度

デフォルトでは、インデックス エントリにはコレクション内のすべてのドキュメントのデータが格納されます。これは、非スパース インデックスと呼ばれます。ドキュメントにインデックスで指定されたフィールドが含まれているかどうかに関係なく、ドキュメントのインデックス エントリが追加されます。 存在しないフィールドは、インデックス エントリの生成時に null 値を持つものとして扱われます。この動作を変更するには、インデックスをスパース インデックスとして定義します。

スパース インデックス

スパース インデックスは、インデックス付きフィールドの少なくとも 1 つに値(null を含む)を含んでいるコレクション内のドキュメントのみをインデックスに登録します。スパース インデックスにより、ストレージの費用を削減して、パフォーマンスを向上させることができます。

配列の内容インデックス

array-contains または array-contains-any を使用して配列フィールドをクエリする際のクエリのパフォーマンスを最適化するには、array-contains モードでフィールドをインデックスに登録します。インデックスに array-contains モードのフィールドを 1 つだけ含めることができます。

array-contains モードで配列フィールドにインデックスを付けると、クエリ エンジンは特定の配列値を含むドキュメントをすばやく見つけることができます。インデックスがない場合、クエリはコレクションのフルスキャンを実行して配列値をチェックします。コレクションのサイズが大きくなるにつれて、クエリのレイテンシと読み取りコストが増加します。

配列フィールドにインデックスを付けるには、フィールドが次の要件を満たしている必要があります。

  • 空でない配列の要件: インデックス エントリは、配列フィールドがドキュメントに存在し、空でない配列である場合にのみ作成されます。フィールドが欠落している、配列でない、または空の配列であるドキュメントはインデックスに登録されません。

密度と array-contains インデックスの関係

array-contains フィールドを含むインデックスの場合、インデックス密度ルールは順序付けされたインデックス付きフィールドにのみ適用されます。空でない配列の要件が満たされている場合、密度ルールはインデックス内の残りの順序付きインデックス フィールドに適用されます。

  • スパース インデックス以外(DENSE): ドキュメントのインデックス エントリが生成されます。インデックスに欠落している順序付きインデックス フィールドは、インデックス エントリに null として保存されます。
  • スパース インデックス(SPARSE): インデックス エントリは、順序付けられたインデックス付きフィールドの少なくとも 1 つがドキュメントに存在する場合にのみ生成されます。

例: インデックス エントリの生成

インデックス users (tags[*], status ASC) を検討します。

ドキュメント NON-SPARSE インデックス SPARSE インデックス
{
  tags: ["news"],
  status: "active"
}
インデックス登録済み:
• (タグ: "news"、ステータス: "active")
インデックス登録済み:
• (タグ: "news"、ステータス: "active")
{
  tags: ["news", "sports"],
  status: "active"
}
インデックス登録済み:
• (タグ: "news"、ステータス: "active")
• (タグ: "sports"、ステータス: "active")
インデックス登録済み:
• (タグ: "news"、ステータス: "active")
• (タグ: "sports"、ステータス: "active")
{
  tags: ["news", "news"],
  status: "active"
}
インデックス登録済み:
• (タグ: "news"、ステータス: "active")(重複除去済み)
インデックス登録済み:
• (タグ: "news"、ステータス: "active")(重複除去済み)
{
  tags: [null],
  status: "active"
}
インデックス登録済み:
• (タグ: null、ステータス: "active")
インデックス登録済み:
• (タグ: null、ステータス: "active")
{
  tags: ["news"]
}
インデックス登録済み:
• (タグ: "news"、ステータス: null)
インデックスに登録されていない(status フィールドがない)
{
  tags: "news",
  status: "active"
}
インデックスに登録されていない(フィールドが配列ではない) インデックス登録なし(フィールドが配列ではない)
{
  tags: null,
  status: "active"
}
インデックス登録なし(フィールドが配列ではない) インデックス登録なし(フィールドが配列ではない)
{
  status: "active"
}
インデックスに登録されていない(tags フィールドがない) インデックスに登録されていない(tags フィールドがない)
{
  tags: [],
  status: "active"
}
インデックスに登録されていない(空の配列) インデックスに登録されていない(空の配列)

クエリの例

ウェブ
// Query for users where 'tags' contains 'news' and 'status' is 'active'
const query = db.collection("users")
  .where("tags", "array-contains", "news")
  .where("status", "==", "active");

// Documents returned by the query:
// [
//   {
//     "id": "alice",
//     "tags": ["news", "tech"],
//     "status": "active"
//   }
// ]

一意のインデックス

一意のインデックス オプションを設定して、インデックス付きフィールドに一意の値を適用します。 複数のフィールドにインデックスが設定されている場合、値の各組み合わせはインデックス全体で一意である必要があります。データベースは、重複する値のインデックス エントリを作成しようとする更新オペレーションや挿入オペレーションを拒否します。インデックス付きフィールドのデータに重複する値が含まれており、一意のインデックスを作成しようとすると、インデックスの構築が失敗し、オペレーションの詳細にエラー メッセージが表示されます。

一意のインデックス内の欠落しているフィールド

一意のインデックスに欠落しているフィールドがあるドキュメントを挿入すると、インデックスは欠落しているフィールドに null 値を設定します。生成されたインデックス エントリは一意である必要があります。一意でない場合、オペレーションは失敗します。

たとえば、次のインデックスがあるとします。

コレクション インデックス登録されるフィールド クエリのスコープ
cities 名前(昇順) コレクション

ドキュメント {"abbreviation": "LA"} をコレクションに追加すると、一意のインデックスによって name が null に設定されたエントリが作成されます。その後、ドキュメント {"abbreviation": "NYC"} を追加しようとすると、一意のインデックスの結果エントリが同じになるため、オペレーションは失敗します。

複数のフィールドを含む一意のインデックスに同じ動作が適用されます。ドキュメントを作成または更新するときに、インデックス付きフィールドが欠落している場合は null に設定され、結果のインデックス エントリはインデックス内で一意である必要があります。

配列値の一意のインデックス

一意の array-contains インデックスは、配列要素が重複するドキュメントを禁止します。

このタイプのインデックスでは、配列に単一のドキュメント内で一意の値が含まれていることは保証されません。

たとえば、tags という名前のフィールドに一意のインデックスがある場合:

次のドキュメント doc1 は、挿入が有効です。

{
  "tags": [ "news", "tech", "news", "music" ]
}

インデックスでは、1 つのドキュメントの同じ配列内で重複する値("news")が許可されます。

重複する要素を含む 2 番目のドキュメント doc2 を挿入しようとすると、オペレーションは失敗します。

{
  "tags": [ "sports", "music" ]
}

"music" は doc1 の配列にすでに存在し、インデックスにマッピングされているため、オペレーションは失敗します。

1 つのドキュメント内の同じ配列内の要素が一意であることを確認する必要がある場合は、アプリケーション ロジックで処理します。

空の配列、欠落しているフィールド、null 値

通常、一意のインデックス内の欠落しているフィールドは null として扱われ、ドキュメント間で一意である必要があります(一意のインデックス内の欠落しているフィールドをご覧ください)。ただし、配列フィールドの一意のインデックスの場合:

  • 空の配列、欠落しているフィールド、スタンドアロンの null: 配列フィールドが空の場合、完全に欠落している場合、またはスタンドアロンの null 値(配列内ではない)を保持している場合、ドキュメントのインデックス キーは生成されません。そのため、複数のドキュメントに空のフィールドやスタンドアロンの null 値を含めることができます。重複キーエラーは発生しません。
  • 配列内の null 要素: 配列に要素として null 値(["news", null] など)が含まれている場合、null 要素はインデックス登録されます。インデックス付き配列フィールドに null 要素を含む後続のドキュメントは、重複キーエラーで失敗します。

インデックス構築エラーのトラブルシューティング

インデックスを管理するときに、インデックス構築エラーが発生することがあります。データベースがデータで問題を検出すると、インデックス作成オペレーションに失敗する可能性があります。 インデックス作成オペレーションは、次の理由で失敗することがあります。

  • インデックスの上限に達しました。たとえば、オペレーションでドキュメントあたりの最大インデックス エントリ数に達した可能性があります。インデックスの作成に失敗すると、エラー メッセージが表示されます。インデックスの上限に達していない場合は、インデックス オペレーションを再試行します。
  • 一意のインデックス オプションを設定しており、インデックス付きフィールドのデータで重複するインデックス エントリが作成されます。続行するには、重複する値の組み合わせをデータから削除します。