Azure Cosmos DB でのインデックス作成ポリシー
適用対象: NoSQL
Azure Cosmos DB では、すべてのコンテナーに、コンテナーの項目のインデックスを作成する方法を指示するインデックス作成ポリシーがあります。 新しく作成したコンテナーの既定のインデックス作成ポリシーでは、あらゆる項目のあらゆるプロパティのインデックスが作成され、任意の文字列または数値に範囲インデックスが適用されます。 これにより、インデックス作成とインデックス管理を事前に考慮することなく、優れたクエリ パフォーマンスを得ることができます。
状況によっては、この自動動作を、自分の要件にさらに適合するようにオーバーライドできます。 "インデックス作成モード" を設定し、"プロパティ パス" を含めるか除外することで、コンテナーのインデックス作成ポリシーをカスタマイズできます。
Note
この記事で説明するインデックス作成ポリシーの更新方法は、Azure Cosmos DB の NoSQL 用 API にのみ適用されます。 インデックス作成については、MongoDB 用 Azure Cosmos DB API に関するページを参照してください
インデックス作成モード
Azure Cosmos DB では 2 つのインデックス作成モードがサポートされます。
- 一貫性: 項目を作成、更新、削除すると、それに同期してインデックスが更新されます。 つまり、読み取りクエリの一貫性は、アカウント用に構成された整合性になります。
- None:コンテナーでインデックス作成が無効になっています。 このモードは、コンテナーがセカンダリ インデックスを必要としない純粋なキー値ストアとして使用される場合に一般的に使用されます。 一括操作のパフォーマンスを改善する目的で使用することもできます。 一括操作が完了したら、インデックス モードを Consistent に設定し、完了まで IndexTransformationProgress を利用して監視できます。
Note
Azure Cosmos DB では、Lazy インデックス作成モードもサポートされます。 Lazy 方式のインデックスではインデックス更新の優先順位が低く、エンジンが他に何も作業をしていないときに実行されます。 結果的に、クエリの結果に一貫性がなくなったり、不完全になったりします。 Azure Cosmos DB コンテナーに対してクエリを実行する場合は、Lazy インデックス作成を選択しないでください。 新しいコンテナーでは、Lazy インデックス作成を選択できません。 cosmosdbindexing@microsoft.com に連絡して、除外を要求することができます (Lazy インデックス作成をサポートしないサーバーレス モードで Azure Cosmos DB アカウントを使用している場合を除きます)。
既定では、インデックス作成ポリシーは automatic
に設定されます。 これはインデックス作成ポリシーの automatic
プロパティを true
に設定することで行います。 このプロパティを true
に設定すると、Azure Cosmos DB で、項目が書き込まれる時点で自動的に項目にインデックスが作成されます。
インデックス サイズ
Azure Cosmos DB の合計使用ストレージは、データ サイズとインデックス サイズ両方の組み合わせです。 インデックス サイズのいくつかの機能を次に示します。
- インデックス サイズは、インデックス作成ポリシーによって異なります。 すべてのプロパティのインデックスが作成されている場合、インデックス サイズはデータ サイズよりも大きくなることがあります。
- データが削除されると、インデックスはほぼ連続して圧縮されます。 ただし、少量のデータを削除する場合は、インデックス サイズの減少をすぐに確認できないことがあります。
- 物理パーティションが分割されると、インデックス サイズが一時的に増大する可能性があります。 インデックス領域は、パーティション分割が完了した後に解放されます。
プロパティ パスを含めるか除外する
カスタム インデックス作成ポリシーには、明示的にインデックス作成に含めるかインデックス作成から除外するプロパティ パスを指定できます。 インデックスが作成されるパスの数を最適化することによって、書き込み操作の待ち時間と RU 料金を大幅に削減できます。 これらのパスは、インデックス作成の概要内のセクションで説明されている方法に従って定義され、以下のように追加されます。
- スカラー値 (文字列または数値) へのパスは
/?
で終わる - 配列の要素は、(
/0
や/1
ではなく)/[]
表記でまとめて処理される /*
ワイルドカードを使用してノードの下の任意の要素を一致させることができる
同じ例をもう一度使用します。
{
"locations": [
{ "country": "Germany", "city": "Berlin" },
{ "country": "France", "city": "Paris" }
],
"headquarters": { "country": "Belgium", "employees": 250 },
"exports": [
{ "city": "Moscow" },
{ "city": "Athens" }
]
}
headquarters
のemployees
パスは/headquarters/employees/?
locations
のcountry
パスは/locations/[]/country/?
headquarters
の下にあるもののパスは/headquarters/*
たとえば、/headquarters/employees/?
パスを含めることができます。 このパスにより employees
プロパティのインデックスが確実に作成されますが、このプロパティ内で入れ子になっている追加の JSON のインデックスは作成されません。
包含/除外戦略
すべてのインデックス作成ポリシーには、含まれるパスまたは除外されるパスのいずれかとしてルート パス /*
を指定する必要があります。
インデックスを作成する必要がないパスを選択的に除外するためにルート パスを指定する。 モデルに追加される可能性がある新しいプロパティのインデックスを Azure Cosmos DB で先を見越して作成できるため、この方法が推奨されます。
インデックスを作成する必要があるパスを選択的に含めるためにルート パスを除外する。 パーティション キーのプロパティ パスは、既定では除外戦略によりインデックスが作成されないため、必要に応じて明示的に含める必要があります。
英数字や _ (アンダースコア) を含む通常文字から成るパスの場合は、パス文字列を二重引用符で囲んでエスケープする必要はありません ("/path/?" など)。 他の特殊文字を含むパスの場合は、パス文字列を二重引用符で囲んでエスケープする必要があります ("/"path-abc"/?" など)。 パスの中に特殊文字が予測される場合は、安全のために、すべてのパスをエスケープすることができます。 機能的には、すべてのパスをエスケープしても、特殊文字を含むパスだけをエスケープしても、違いはまったくありません。
システム プロパティ
_etag
は、etag がインデックス作成対象パスに追加されていない限り、既定でインデックス作成から除外されます。インデックス作成モードが [consistent](同期) に設定されている場合、システム プロパティ
id
と_ts
には自動的にインデックスが作成されます。明示的にインデックスされたパスが項目に存在しない場合は、パスが未定義であることを示す値がインデックスに追加されます。
明示的に含まれるすべてのパスには、特定の項目についてパスが未定義の場合でも、コンテナー内の各項目についてインデックスに値が追加されます。
パスを含めたり除外したりするためのインデックス作成ポリシーの例については、こちらのセクションを参照してください。
優先順位を含める、または除外する
含まれるパスと除外されるパスに競合がある場合は、より正確なパスが優先されます。
次に例を示します。
含まれるパス: /food/ingredients/nutrition/*
除外されるパス: /food/ingredients/*
この場合、含まれるパスはより正確であるため、除外されるパスよりも優先されます。 これらのパスに基づいて、food/ingredients
パス内または入れ子になっているすべてのデータは、インデックスから除外されます。 例外は、含まれるパス /food/ingredients/nutrition/*
内のデータで、インデックスが作成されます。
Azure Cosmos DB の含まれるパスと除外されるパスの優先順位に関するいくつかの規則を次に示します。
より深いパスは、浅いパスよりも正確です。 たとえば、
/a/b/?
は/a/?
よりも正確です。/?
は/*
よりも正確です。 たとえば/a/?
は/a/*
よりも正確であるため、/a/?
が優先されます。パス
/*
には、含まれるパスまたは除外されるパスを指定する必要があります。
フルテキスト インデックス
Note
フルテキスト インデックスを指定するには、NoSQL API のフルテキスト検索およびハイブリッド検索のプレビュー機能を有効にする必要があります。
フルテキスト インデックスを使用すると、インデックスを使用してフルテキスト検索とスコアリングを効率的に行うことができます。 インデックスを作成するすべてのテキスト パスを含む、インデックス作成ポリシーの fullTextIndexes
セクションを含めることで、インデックス作成ポリシーでフルテキスト パスを簡単に定義することができます。 次に例を示します。
{
"indexingMode": "consistent",
"automatic": true,
"includedPaths": [
{
"path": "/*"
}
],
"excludedPaths": [
{
"path": "/\"_etag\"/?"
},
],
"fullTextIndexes": [
{
"path": "/text"
}
]
}
重要
フルテキスト インデックス作成ポリシーは、コンテナーのフルテキスト ポリシーで定義されているパス上に存在する必要があります。 コンテナーのベクトル ポリシーの詳細を参照してください。
ベクトル インデックス
Note
ベクトル インデックスを指定するには、Azure Cosmos DB NoSQL ベクトル検索機能を有効にする必要があります。
ベクトル インデックス作成では、VectorDistance
システム関数を使用して、ベクトル検索の実行効率を向上させます。 ベクトル検索は、ベクトル インデックス作成を適用することで、待機時間を短縮し、スループットを高め、RU 消費を削減します。 次の種類のベクトル インデックス ポリシーを指定できます。
型 | 説明 | 最大ディメンション |
---|---|---|
flat |
他のインデックス プロパティと同じインデックスにベクトルを格納します。 | 505 |
quantizedFlat |
インデックスに格納する前にベクトルを量子化 (圧縮) します。 これにより、わずかな精度を犠牲にして、待機時間とスループットを向上させることができます。 | 4096 |
diskANN |
高速かつ効率的な概算検索のために、DiskANN に基づいてインデックスを作成します。 | 4096 |
重要
現在、ベクトル ポリシーとベクトル インデックスは、作成後に変更できません。 変更するには、新しいコレクションを作成してください。
注意すべき点をいくつか次に示します。
flat
およびquantizedFlat
インデックスの種類は、Azure Cosmos DB のインデックスを適用して、ベクトル検索の実行時に各ベクトルを格納し、読み取ります。flat
インデックスを持つベクトル検索はブルート フォース検索であり、100% の精度または再現率を生み出します。 つまり、データセットで最も類似したベクトルを見つけることが保証されています。 ただし、フラット インデックス上のベクトルには505
次元の制限があります。quantizedFlat
インデックスには、量子化された(圧縮された)ベクトルが格納されます。quantizedFlat
インデックスを使用したベクトル検索もブルート フォース検索ですが、インデックスに追加する前にベクトルが量子化されるため、精度は 100% をわずかに下回る可能性があります。 ただし、quantized flat
を使用したベクトル検索はflat
インデックスでのベクトル検索よりも待機時間が短く、スループットが高く、RU コストが低くなります。 これは、クエリ フィルターを使用してベクトル検索を比較的小さなベクトル セットにフィルター処理し、高い精度が要求されるシナリオに適したオプションです。diskANN
インデックスは、Microsoft Research によって開発されたハイ パフォーマンス ベクトル インデックス作成アルゴリズム スイートである DiskANN を適用する、ベクトル専用に定義された個別のインデックスです。 DiskANN インデックスでは、高い精度を維持しながら、最短の待機時間、最高のスループット、および最小の RU コスト クエリが提供されます。 しかし、DiskANN は近似ニアレストネイバー (ANN) インデックスであるため、精度はquantizedFlat
やflat
よりも低くなる可能性があります。
diskANN
インデックスと quantizedFlat
インデックスは、すべての近似最近傍ベクトル インデックスに適用される精度と待機時間のトレードオフを調整するために使用できる、オプションのインデックス構築パラメーターを取ることができます。
quantizationByteSize
: 直積量子化のサイズ (バイト単位) を設定します。 最小値 = 1、規定値 = 動的 (システムが決定)、最大値 = 512。 この値が高いほど、RU コストが高くなり、待機時間が長くなる代わりに、ベクトル検索の精度が高くなる可能性があります。 これは、quantizedFlat
とDiskANN
の両方のインデックスの種類に適用されます。indexingSearchListSize
: インデックスの構築中に検索するベクトルの数を設定します。 最小値 = 10、規定値 = 100、最大値 = 500。 この値が高いほど、インデックスのビルド時間が長くなり、ベクトルの取り込みの待機時間が長くなる代わりに、ベクトル検索の精度が高くなる可能性があります。 これは、DiskANN
インデックスにのみ適用されます。
ベクトル インデックスを使用したインデックス作成ポリシーの例を次に示します。
{
"indexingMode": "consistent",
"automatic": true,
"includedPaths": [
{
"path": "/*"
}
],
"excludedPaths": [
{
"path": "/_etag/?",
},
{
"path": "/vector/*"
}
],
"vectorIndexes": [
{
"path": "/vector",
"type": "diskANN"
}
]
}
重要
ベクトル インデックス作成ポリシーは、コンテナーのベクトル ポリシーで定義されているパス上に存在する必要があります。 コンテナーのベクトル ポリシーの詳細を参照してください。
重要
挿入の最適なパフォーマンスを確保するためにインデックス作成ポリシーの "excludedPaths" セクションに追加されたベクトル パス。 ベクトル パスを "excludedPaths" に追加しないと、ベクトル挿入に対してより高い RU 料金と待機時間が発生します。
空間インデックス
インデックス作成ポリシーで空間パスを定義する場合は、そのパスに適用するインデックスの type
を定義する必要があります。 空間インデックスには、次のような種類があります。
ポイント
多角形
MultiPolygon
LineString
Azure Cosmos DB では、既定で空間インデックスは作成されません。 空間 SQL 組み込み関数を使用する場合は、必要なプロパティに対して空間インデックスを作成する必要があります。 空間インデックスを追加するためのインデックス作成ポリシーの例については、このセクションを参照してください。
タプル インデックス
タプル インデックスは、配列要素内の複数のフィールドに対してフィルター処理を実行する場合に便利です。 タプル インデックスは、タプル指定子 "[]" を使用してインデックス作成ポリシーの includedPaths セクションで定義されます。
Note
含まれるパスまたは除外されるパスとは異なり、/* ワイルドカードを使用してパスを作成することはできません。 すべてのタプル パスは "/?" で終わる必要があります。 タプル パス内のタプルが項目に存在しない場合は、そのタプルが未定義であることを示す値がインデックスに追加されます。
配列タプル パスは includedPaths セクションで定義され、以下の記法を使用します。
<path prefix>/[]/{<tuple 1>, <tuple 2> … <tuple n>}/?
以下の点に注意してください。
- 最初の部分であるパス プレフィックスは、タプル間で共通のパスです。 これは、ルートから配列へのパスです。 この例では、"/events" です。
- その次が、配列ワイルドカード指定子 "[]" です。 配列タプル パスには、タプル指定子 "{}" の前に配列ワイルドカード指定子が必ず必要です。
- その次に、タプル指定子 "{}" を使用してタプルを指定します。
- タプルはコンマで区切られます。
- タプルは、以下のいくつかの例外を除き、他のインデックス パスと同じパス仕様を使用する必要があります。
- タプルの先頭を "/" で始めることはできません。
- タプルには配列ワイルドカードを使用できません。
- タプルの末尾を "?" または “*” にすることはできません。
- “?” はタプル パスの最後のセグメントであり、タプル指定子セグメントの直後に指定する必要があります。
たとえば、 にします。
/events/[]/{name, category}/?
"有効" な配列タプル パスの例をいくつか次に示します。
“includedPaths”:[
{“path”: “/events/[]/{name/first, name/last}/?”},
{“path”: “/events/[]/{name/first, category}/?”},
{“path”: “/events/[]/{name/first, category/subcategory}/?”},
{“path”: “/events/[]/{name/[1]/first, category}/?”},
{“path”: “/events/[]/{[1], [3]}/?”},
{“path”: “/city/[1]/events/[]/{name, category}/?”}
]
"無効" な配列タプル パスの例をいくつか次に示します。
/events/[]/{name/[]/first, category}/?
- タプルの 1 つに配列ワイルドカードが使用されています
/events/[]/{name, category}/*
- 配列タプル パスの最後のセグメントは * ではなく "?" である必要があります
/events/[]/{{name, first},category}/?
- タプル指定子が入れ子になっています
/events/{name, category}/?
- 配列ワイルドカードがタプル指定子の前にありません
/events/[]/{/name,/category}/?
- タプルが
/
で始まっています
- タプルが
/events/[]/{name/?,category/?}/?
- タプルが
?
で終わっています
- タプルが
/city/[]/events/[]/{name, category}/?
- パスのプレフィックスに 2 つの配列ワイルドカードが含まれています
複合インデックス
2 つ以上のプロパティを使用する ORDER BY
句が含まれるクエリには、複合インデックスが必要です。 また、複合インデックスを定義して、多くの等値クエリと範囲クエリのパフォーマンスを向上させることもできます。 既定では、複合インデックスは定義されないため、必要に応じて複合インデックスを追加する必要があります。
含まれるパスまたは除外されるパスとは異なり、/*
ワイルドカードを使用してパスを作成することはできません。 すべての複合パスには、指定する必要のないパスの末尾に暗黙的な /?
があります。 複合パスは、複合インデックスに含まれる唯一の値であるスカラー値になります。 複合インデックスにあるパスが項目に存在しない場合、または非スカラー値を示す場合は、パスが未定義であることを示す値がインデックスに追加されます。
複合インデックスを定義する場合は、次のものを指定します。
2 つ以上のプロパティ パス。 プロパティ パスが定義されるシーケンスが重要です。
順序 (昇順または降順)。
Note
複合インデックスを追加したとき、新しい複合インデックスの追加が完了するまで、クエリは既存の範囲インデックスを利用します。 そのため、複合インデックスを追加しても、すぐにパフォーマンス向上が見られないことがあります。 いずれかの SDK を使用して、インデックス変換の進行状況を追跡できます。
複数のプロパティに対する ORDER BY クエリ:
2 つ以上のプロパティを使用する ORDER BY
句が含まれるクエリに複合インデックスを使用する場合は、次の考慮事項を確認します。
複合インデックスのパスが
ORDER BY
句の中のプロパティのシーケンスに一致しない場合、その複合インデックスはクエリをサポートできません。複合インデックスのパスの順序 (昇順または降順) は、
ORDER BY
句の中のorder
とも一致する必要があります。複合インデックスはまた、すべてのパスで反対の順序を持つ
ORDER BY
句もサポートします。
複合インデックスがプロパティ name、age、および _ts に対して定義されている次の例を考えてみます。
複合インデックス | サンプルの ORDER BY クエリ |
複合インデックスでサポートされているか |
---|---|---|
(name ASC, age ASC) |
SELECT * FROM c ORDER BY c.name ASC, c.age asc |
Yes |
(name ASC, age ASC) |
SELECT * FROM c ORDER BY c.age ASC, c.name asc |
No |
(name ASC, age ASC) |
SELECT * FROM c ORDER BY c.name DESC, c.age DESC |
Yes |
(name ASC, age ASC) |
SELECT * FROM c ORDER BY c.name ASC, c.age DESC |
No |
(name ASC, age ASC, timestamp ASC) |
SELECT * FROM c ORDER BY c.name ASC, c.age ASC, timestamp ASC |
Yes |
(name ASC, age ASC, timestamp ASC) |
SELECT * FROM c ORDER BY c.name ASC, c.age ASC |
No |
すべての必要な ORDER BY
クエリに対応できるように、インデックス作成ポリシーをカスタマイズする必要があります。
複数のプロパティに対するフィルターを含むクエリ
クエリに 2 つ以上のプロパティに対するフィルターが含まれている場合は、これらのプロパティの複合インデックスを作成すると便利な場合があります。
たとえば、等値および範囲の両方のフィルターが含まれる次のクエリについて考えてみます。
SELECT *
FROM c
WHERE c.name = "John" AND c.age > 18
このクエリは、(name ASC, age ASC)
の複合インデックスを適用できる場合、時間が短縮され、RU の消費が少なくなるため、より効率的に実行できます。
範囲フィルターが複数含まれるクエリを複合インデックスを使用して最適化することもできます。 ただし、個々の複合インデックスで最適化できる範囲フィルターはそれぞれ 1 つだけです。 範囲フィルターは、>
、<
、<=
、>=
、!=
です。 範囲フィルターは、複合インデックス内で最後に定義する必要があります。
等値フィルターが 1 つと範囲フィルターが 2 つ含まれる次のクエリについて考えてみます。
SELECT *
FROM c
WHERE c.name = "John" AND c.age > 18 AND c._ts > 1612212188
このクエリは、(name ASC, age ASC)
と (name ASC, _ts ASC)
の複合インデックスを使用すると、より効率的に実行できます。 ただし、等値フィルターが含まれるプロパティを複合インデックス内で最初に定義する必要があるため、クエリでは (age ASC, name ASC)
の複合インデックスが使用されません。 各複合インデックスで最適化できる範囲フィルターは 1 つだけであるため、(name ASC, age ASC, _ts ASC)
の複合インデックスを 1 つだけではなく、個別の複合インデックスを 2 つ必要とします。
複数のプロパティに対するフィルターが含まれるクエリ用に複合インデックスを作成する場合は、次の考慮事項を確認します。
- フィルター式では、複数の複合インデックスを使用できます。
- クエリのフィルター内のプロパティは、複合インデックス内のプロパティと一致している必要があります。 複合インデックスにプロパティが含まれていても、クエリにフィルターとして含まれていない場合、このクエリでは複合インデックスは使用されません。
- 複合インデックスで定義されていない他のプロパティがフィルターに含まれているクエリの場合は、複合インデックスと範囲インデックスの組み合わせを使用してクエリが評価されます。 この場合、範囲インデックスのみ使用する場合よりも、必要な RU が少なくなります。
- プロパティに範囲フィルター (
>
、<
、<=
、>=
、または!=
) が含まれている場合、このプロパティは複合インデックス内で最後に定義する必要があります。 クエリに複数の範囲フィルターが含まれている場合、複数の複合インデックスを利用すると効果的になる可能性があります。 - 複数のフィルターが含まれるクエリを最適化するために複合インデックスを作成する場合、複合インデックスの
ORDER
は結果に影響しません。 このプロパティは省略可能です。
複合インデックスがプロパティ name、age、および timestamp に対して定義されている次の例を考えてみます。
複合インデックス | サンプル クエリ | 複合インデックスでサポートされているか |
---|---|---|
(name ASC, age ASC) |
SELECT * FROM c WHERE c.name = "John" AND c.age = 18 |
Yes |
(name ASC, age ASC) |
SELECT * FROM c WHERE c.name = "John" AND c.age > 18 |
Yes |
(name ASC, age ASC) |
SELECT COUNT(1) FROM c WHERE c.name = "John" AND c.age > 18 |
Yes |
(name DESC, age ASC) |
SELECT * FROM c WHERE c.name = "John" AND c.age > 18 |
Yes |
(name ASC, age ASC) |
SELECT * FROM c WHERE c.name != "John" AND c.age > 18 |
No |
(name ASC, age ASC, timestamp ASC) |
SELECT * FROM c WHERE c.name = "John" AND c.age = 18 AND c.timestamp > 123049923 |
Yes |
(name ASC, age ASC, timestamp ASC) |
SELECT * FROM c WHERE c.name = "John" AND c.age < 18 AND c.timestamp = 123049923 |
No |
(name ASC, age ASC) and (name ASC, timestamp ASC) |
SELECT * FROM c WHERE c.name = "John" AND c.age < 18 AND c.timestamp > 123049923 |
Yes |
フィルターと ORDER BY を使用したクエリ
クエリで 1 つ以上のプロパティがフィルター処理され、ORDER BY 句に異なるプロパティが含まれている場合は、フィルター内のプロパティを ORDER BY
句に追加すると便利な場合があります。
たとえば、フィルター内のプロパティを ORDER BY
句に追加すると、複合インデックスを適用するために次のクエリを書き直すことができます。
範囲インデックスを使用するクエリ:
SELECT *
FROM c
WHERE c.name = "John"
ORDER BY c.timestamp
複合インデックスを使用するクエリ:
SELECT *
FROM c
WHERE c.name = "John"
ORDER BY c.name, c.timestamp
フィルターを使用した任意の ORDER BY
クエリに対しても同じクエリ最適化を一般化できます。このとき、個々の複合インデックスでサポートできる範囲フィルターは最大で 1 つだけであることに注意してください。
範囲インデックスを使用するクエリ:
SELECT *
FROM c
WHERE c.name = "John" AND c.age = 18 AND c.timestamp > 1611947901
ORDER BY c.timestamp
複合インデックスを使用するクエリ:
SELECT *
FROM c
WHERE c.name = "John" AND c.age = 18 AND c.timestamp > 1611947901
ORDER BY c.name, c.age, c.timestamp
さらに、複合インデックスを使用して、システム関数と ORDER BY を含むクエリを最適化することができます。
範囲インデックスを使用するクエリ:
SELECT *
FROM c
WHERE c.firstName = "John" AND Contains(c.lastName, "Smith", true)
ORDER BY c.lastName
複合インデックスを使用するクエリ:
SELECT *
FROM c
WHERE c.firstName = "John" AND Contains(c.lastName, "Smith", true)
ORDER BY c.firstName, c.lastName
次の考慮事項は、フィルターと ORDER BY
句が含まれるクエリを最適化するために複合インデックスを作成する場合に適用されます。
- 1 つのプロパティに対するフィルターと、異なるプロパティを使用する別の
ORDER BY
句が含まれるクエリに対して複合インデックスを定義しなかった場合でも、クエリは成功します。 しかし、複合インデックスを使用すると、特にORDER BY
句内のプロパティのカーディナリティが高い場合、クエリの RU コストを削減できます。 - クエリでプロパティをフィルター処理する場合は、最初にこれらのプロパティを
ORDER BY
句に含める必要があります。 - クエリで複数のプロパティをフィルター処理する場合は、等値フィルターを
ORDER BY
句内で最初のプロパティとする必要があります。 - クエリで複数のプロパティをフィルター処理する場合、複合インデックスごとに使用できる範囲フィルターまたはシステム関数の数は最大で 1 つとなります。 範囲フィルターまたはシステム関数で使用するプロパティは、複合インデックス内で最後に定義する必要があります。
- 複合インデックスを、複数のプロパティが含まれる
ORDER BY
クエリ、および複数のプロパティに対するフィルターが含まれるクエリに対して作成する際の考慮事項もすべて、適用されます。
複合インデックス | サンプルの ORDER BY クエリ |
複合インデックスでサポートされているか |
---|---|---|
(name ASC, timestamp ASC) |
SELECT * FROM c WHERE c.name = "John" ORDER BY c.name ASC, c.timestamp ASC |
Yes |
(name ASC, timestamp ASC) |
SELECT * FROM c WHERE c.name = "John" AND c.timestamp > 1589840355 ORDER BY c.name ASC, c.timestamp ASC |
Yes |
(timestamp ASC, name ASC) |
SELECT * FROM c WHERE c.timestamp > 1589840355 AND c.name = "John" ORDER BY c.timestamp ASC, c.name ASC |
No |
(name ASC, timestamp ASC) |
SELECT * FROM c WHERE c.name = "John" ORDER BY c.timestamp ASC, c.name ASC |
No |
(name ASC, timestamp ASC) |
SELECT * FROM c WHERE c.name = "John" ORDER BY c.timestamp ASC |
No |
(age ASC, name ASC, timestamp ASC) |
SELECT * FROM c WHERE c.age = 18 and c.name = "John" ORDER BY c.age ASC, c.name ASC,c.timestamp ASC |
Yes |
(age ASC, name ASC, timestamp ASC) |
SELECT * FROM c WHERE c.age = 18 and c.name = "John" ORDER BY c.timestamp ASC |
No |
フィルターと集計を使用したクエリ
クエリが 1 つ以上のプロパティをフィルター処理し、集計システム関数を持つ場合は、フィルターおよび集計システム関数のプロパティの複合インデックスを作成すると便利な場合があります。 この最適化は、SUM および AVG システム関数に適用されます。
次の考慮事項は、フィルターと集計システム関数が含まれるクエリを最適化するために複合インデックスを作成する場合に適用されます。
- 複合インデックスは、集計を使用したクエリを実行するときは省略可能です。 しかし、複合インデックスを使用すると、クエリの RU コストを削減できる場合がよくあります。
- クエリで複数のプロパティをフィルター処理する場合、等値フィルターを複合インデックスの最初のプロパティとする必要があります。
- 範囲フィルターを複合インデックスごとに最大で 1 つ設定でき、それを集計システム関数のプロパティに指定する必要があります。
- 集計システム関数のプロパティは、複合インデックス内で最後に定義する必要があります。
order
(ASC
またはDESC
) は関係ありません。
複合インデックス | サンプル クエリ | 複合インデックスでサポートされているか |
---|---|---|
(name ASC, timestamp ASC) |
SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" |
Yes |
(timestamp ASC, name ASC) |
SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" |
No |
(name ASC, timestamp ASC) |
SELECT AVG(c.timestamp) FROM c WHERE c.name > "John" |
No |
(name ASC, age ASC, timestamp ASC) |
SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" AND c.age = 25 |
Yes |
(age ASC, timestamp ASC) |
SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" AND c.age > 25 |
No |
配列ワイルドカードを使用した複合インデックス
配列ワイルドカードを含む複合インデックスの例を次に示します。
{
"automatic":true,
"indexingMode":"Consistent",
"includedPaths":[
{
"path":"/*"
}
],
"excludedPaths":[],
"compositeIndexes":[
[
{"path":"/familyname", "order":"ascending"},
{"path":"/children/[]/age", "order":"descending"}
]
]
}
この複合インデックスを利用できるクエリの例を次に示します。
SELECT r.id
FROM root r
JOIN ch IN r.children
WHERE r.familyname = 'Anderson' AND ch.age > 20
インデックス作成ポリシーの変更
コンテナーのインデックス作成ポリシーは、Azure portal またはサポートされている SDK のいずれかを使用していつでも更新できます。 インデックス作成ポリシーを更新すると、古いインデックスから新しいものへの変換がトリガーされ、オンラインでその場で実行されます (そのため、この操作中に記憶域が追加で消費されることはありません)。 古いインデックス作成ポリシーは、新しいポリシーに効率的に変換され、コンテナー上での書き込み可用性、読み取り可用性、またはプロビジョニングされたスループットが影響を受けることはありません。 インデックス変換は非同期操作であり、完了までにかかる時間は、プロビジョニングされたスループット、項目の数、およびそれらのサイズによって決まります。 複数のインデックス作成ポリシーの更新を行う必要がある場合は、インデックスの変換ができるだけ早く完了するように、すべての変更を 1 回の操作として実行することをお勧めします。
重要
インデックス変換は要求ユニットを消費する操作です。
Note
インデックス変換の進行状況は、Azure portal で、またはいずれかの SDK を使用して追跡できます。
インデックス変換中に、書き込み可用性への影響はありません。 インデックス変換にはプロビジョニングされた RU が使用されますが、CRUD 操作やクエリよりも低い優先順位になります。
新しいインデックス付きパスを追加するときに、読み取り可用性への影響がありません。 クエリで新しいインデックス付きパスが使用されるのは、インデックス変換が完了してからです。 つまり新しいインデックス付きパスを追加しているとき、そのインデックス付きパスの恩恵を受けるクエリのパフォーマンスは、インデックス変換の前と途中では同じです。 インデックス変換が完了すると、クエリ エンジンは新しいインデックス付きパスを使用し始めます。
インデックス付きパスを削除しているときは、すべての変更を 1 つのインデックス作成ポリシー変換にまとめる必要があります。 1 回のインデックス作成ポリシーの変更で、複数のインデックスを削除する場合は、クエリ エンジンによって、インデックス変換全体で結果の整合性と完全性が提供されます。 ただし、複数回のインデックス作成ポリシーの変更を通じてインデックスを削除する場合、クエリ エンジンでは、すべてのインデックス変換が完了するまで、結果の整合性または完全性は提供されません。 ほとんどの開発者は、インデックスの削除後、これらのインデックスを使用するクエリをすぐに実行しようとはしません。実際には、このような状況になることはほとんどありません。
インデックス付きパスを破棄すると、クエリ エンジンはすぐに使用するのを止めて、代わりにフル スキャンを実行します。
Note
可能であれば、複数のインデックス削除を 1 回のインデックス作成ポリシーの変更にグループ化しようとする必要があります。
重要
インデックスの削除は直ちに反映されますが、新しいインデックスの追加は、インデックス作成変換が必要であるため、しばらく時間がかかります。 1 つのインデックスを別のインデックスに置き換える場合 (たとえば、単一のプロパティ インデックスを複合インデックスに置き換える場合)、まず新しいインデックスを最初に追加し、インデックスの変換が完了するのを待ってから、以前のインデックスをインデックス作成ポリシーから削除するようにしてください。 そうしないと、前のインデックスに対してクエリを実行する機能に悪影響が及び、前のインデックスを参照するアクティブなワークロードが中断される可能性があります。
インデックス作成ポリシーと TTL
Time-to-Live (TTL) 機能を使用するには、インデックス作成が必要です。 これは、次のことを意味します。
- インデックス作成モードが
none
に設定されているコンテナーで、TTL をアクティブにすることはできません。 - TTL がアクティブになっているコンテナーで、インデックス作成モードを [なし] に設定することはできません。
インデックス作成が必要なプロパティ パスはないものの、TTL が必要なシナリオでは、インデックス作成モードが consistent
に設定され、パスが含まれておらず、/*
が除外された唯一のパスとなっているインデックス作成ポリシーを使用できます。