Azure Cosmos DB コンテナーのクエリを実行する

適用対象: NoSQL

この記事では、Azure Cosmos DB のコンテナー (コレクション、グラフ、またはテーブル) のクエリを実行する方法について説明します。 特に、Azure Cosmos DB でのインパーティション クエリとクロスパーティション クエリの動作について説明します。

インパーティション クエリ

コンテナーのデータのクエリを実行するとき、クエリでパーティション キー フィルターを指定すると、Azure Cosmos DB によってクエリが自動的に最適化されます。 クエリは、フィルターで指定されているパーティション キーの値に対応する物理パーティションにルーティングされます。

たとえば、DeviceId に対する等値フィルターが含まれる次のようなクエリについて考えます。 DeviceId でパーティション分割されたコンテナーに対してこのクエリを実行した場合、このクエリは、フィルターによって対象を 1 つの物理パーティションに絞り込みます。

SELECT * FROM c WHERE c.DeviceId = 'XMS-0001'

前の例と同様に、このクエリでもフィルターによって対象を 1 つのパーティションに絞り込みます。 Location にフィルターを追加しても、次のクエリは変更されません。

SELECT * FROM c WHERE c.DeviceId = 'XMS-0001' AND c.Location = 'Seattle'

次に示すクエリでは、パーティション キーに対する範囲フィルターがあり、1 つの物理パーティションにスコープされません。 インパーティション クエリにするには、クエリにパーティション キーを含む等値フィルターが必要です。

SELECT * FROM c WHERE c.DeviceId > 'XMS-0001'

クロスパーティション クエリ

次のクエリには、パーティション キー (DeviceId) に対するフィルターがありません。 そのため、すべての物理パーティションにファンアウトし、各パーティションのインデックスに対して実行されます。

SELECT * FROM c WHERE c.Location = 'Seattle`

各物理パーティションには、独自のインデックスがあります。 そのため、コンテナーに対してクロスパーティション クエリを実行すると、実質的には物理パーティション "ごと" に 1 つのクエリが実行されることになります。 Azure Cosmos DB によって、異なる物理パーティションにまたがる結果が自動的に集計されます。

異なる物理パーティション内のインデックスは、互いに独立しています。 Azure Cosmos DB にはグローバル インデックスはありません。

並列クロスパーティション クエリ

Azure Cosmos DB SDK 1.9.0 以降では、並列クエリ実行オプションがサポートされています。 並列パーティション間クエリを使用すれば、複数のパーティションにまたがるクエリでも、少ない待ち時間で実行できます。

次のパラメーターを調整することで、並列クエリの実行を管理できます。

  • MaxConcurrency: コンテナーのパーティションに対する同時ネットワーク接続数の上限を設定します。 このプロパティを -1 に設定した場合、SDK によって並列処理次数が管理されます。 MaxConcurrency0 に設定されている場合は、コンテナーのパーティションに対して 1 つのネットワーク接続が存在します。

  • MaxBufferedItemCount: クエリの待ち時間とクライアント側のメモリ使用率のバランスを調整します。 このオプションを省略するか -1 に設定した場合、並列クエリの実行中にバッファリングされる項目の数は SDK によって管理されます。

Azure Cosmos DB ではクロスパーティション クエリを並列化できるため、クエリの待機時間は通常、システムによって物理パーティションが追加されると適切にスケーリングされます。 ただし、物理パーティションの総数が増えるにつれて、RU 使用量は大幅に増加します。

クロスパーティション クエリを実行する場合、基本的には個々の物理パーティションごとに個別のクエリを実行することになります。 クロスパーティション クエリでは、利用可能な場合にはインデックスを使用しますが、それでもインパーティション クエリほど効率的ではありません。

便利な例

クロスパーティション クエリをわかりやすく説明するために、次のような例えがあります。

あなたは配送ドライバーで、さまざまなアパートに荷物を配達する必要があるとします。 各アパートの敷地内には、すべての居住者の部屋番号が記載されたリストがあります。 各アパートは物理パーティション、各リストは物理パーティションのインデックスと考えることができます。

この例を使用して、インパーティション クエリとクロスパーティション クエリを比較できます。

インパーティション クエリ (例)

配送ドライバーが適切なアパート (物理パーティション) を認識している場合は、すぐに正しい建物に向かうことができます。 ドライバーは、そのアパートの居住者の部屋番号 (インデックス) のリストを確認し、適切な荷物を迅速に配達できます。 この場合、ドライバーは、アパートまで行って荷物の受取人がそこに住んでいるかどうかを確認するのに、無駄な時間や労力を使わなくて済みます。

クロスパーティション クエリ (ファンアウト)

配送ドライバーが正しいアパート (物理パーティション) を知らない場合は、すべてのアパートを 1 つずつ訪ねて、すべての居住者の部屋番号 (インデックス) が記載されたリストを確認する必要があります。 ドライバーは、各アパートに到着したら、各居住者の住所のリストを使用できます。 ただし、荷物の受取人がそこに住んでいるかどうかにかかわらず、すべてのアパートのリストを確認する必要があります。 これがクロスパーティション クエリの仕組みです。 インデックスを使用することはできますが (すべてのドアをノックする必要はありません)、すべての物理パーティションでインデックスを個別に確認する必要があります。

クロスパーティション クエリ (少数の物理パーティションにのみスコープされている)

荷物のすべての受取人が特定のいくつかのアパートに住んでいることを配送ドライバーが知っている場合、すべてのアパートに行く必要はありません。 いくつかのアパートに行くには 1 つの建物だけに行くより多くの作業が必要になりますが、それでもかなりの時間と労力を節約できます。 クエリのフィルターに IN キーワードを使用したパーティション キーが含まれる場合、関連する物理パーティションのインデックスに対してのみデータをチェックします。

クロス パーティション クエリを回避する

ほとんどのコンテナーでは、いくつかのクロスパーティション クエリを使用することは避けられません。これは問題ありません。 ほぼすべてのクエリ操作で、論理パーティション キーと物理パーティションの両方について、パーティションをまたぐことがサポートされています。 また、Azure Cosmos DB では、複数の物理パーティションを対象とするクエリ実行を並列化するための多くの最適化が、クエリ エンジンとクライアント SDK に用意されています。

読み取り量の多いほとんどのシナリオでは、クエリ フィルターで最も一般的なプロパティを選択することをお勧めします。 また、パーティション キーが他のパーティション キー選択のベスト プラクティスに従っていることを確認する必要もあります。

通常、クロスパーティション クエリの回避は大規模なコンテナーだけの問題です。 物理パーティションのインデックスで結果を確認するたびに、クエリのフィルターと一致する項目がその物理パーティションにない場合であっても、少なくとも約 2.5 RU の料金がかかります。 そのため、物理パーティションが 1 つ (またはごく少数) しかない場合は、クロスパーティション クエリがインパーティション クエリより大幅に多くの RU を使用することはありません。

物理パーティションの数は、プロビジョニングされた RU の量に関連付けられています。 各物理パーティションでは、最大 10,000 RU をプロビジョニングでき、最大 50 GB のデータを格納できます。 物理パーティションは、Azure Cosmos DB によって自動的に管理されます。 コンテナー内の物理パーティションの数は、プロビジョニングされたスループットと使用されているストレージに依存します。

ワークロードが以下の条件を満たしている場合は、クロスパーティション クエリを避けるようにしてください。

  • 30,000 より多くの RU をプロビジョニングする予定である
  • 100 GB を超えるデータを格納する予定である

次のステップ

Azure Cosmos DB でのパーティション分割については、次の記事を参照してください。