Using Global Secondary Indexes in DynamoDB - Amazon DynamoDB

英語の翻訳が提供されている場合で、内容が矛盾する場合には、英語版がオリジナルとして取り扱われます。翻訳は機械翻訳により提供されています。

Using Global Secondary Indexes in DynamoDB

アプリケーションによっては、さまざまな属性をクエリ基準に使用して、いろいろな種類のクエリを実行する必要があります。これらの要件をサポートするには、 global secondary indexes および課題 Query これらのインデックスに対するリクエスト Amazon DynamoDB.

Scenario: Using a Global Secondary Index

たとえば、GameScores という名前のテーブルがあり、モバイルゲームアプリケーションのユーザーとスコアを記録しているとします。GameScores の各項目は、パーティションキー (UserId) およびソートキー (GameTitle) で特定されます。次の図は、テーブル内の項目の構成を示しています。一部表示されていない属性もあります。


                ユーザー ID、タイトル、スコア、日付、および勝敗のリストを含む GameScores テーブル。

ここで、各ゲームの最高スコアを表示する順位表アプリケーションを作成すると仮定します。キー属性 (UserIdGameTitle) を指定したクエリは非常に効率的です。ただし、アプリケーションが GameTitle だけに基づいて GameScores からデータを取り出す必要がある場合、Scan オペレーションを使用する必要があります。テーブルに追加される項目が増えるにつれ、すべてのデータのスキャンは低速で非効率的になります。このため、次のような質問に答えることが難しくなります。

  • What is the top score ever recorded for the game Meteor Blasters?

  • Which user had the highest score for Galaxy Invaders?

  • What was the highest ratio of wins vs. losses?

非キー属性に対するクエリの速度を上げるために、グローバルセカンダリインデックス を作成できます。グローバルセカンダリインデックスには、ベーステーブルからの属性の一部が格納されますが、テーブルのプライマリキーとは異なるプライマリキーによって構成されます。インデックスキーは、テーブルからのキー属性を持つ必要がありません。また、テーブルと同じキースキーマを使用する必要もありません。

たとえば、 グローバルセカンダリインデックス 名前付き GameTitleIndex、パーティション キー付き GameTitle そして TopScore。 基本テーブルの主要アトリビュートは常にインデックスに投影されるため、 UserId 属性も存在します。次の図は、GameTitleIndex インデックスを示しています。


                タイトル、スコア、およびユーザー ID のリストを含む GameTitleIndex テーブル。

これで、GameTitleIndex に対してクエリを実行し、Meteor Blasters のスコアを簡単に入手できるようになります。結果は、ソートキーの値、 TopScore。 _を設定すると、 ScanIndexForward パラメーターを false に設定すると、結果は降順で返されるため、最高スコアが最初に返されます。

すべてのグローバルセカンダリインデックスには、パーティションキーが必要で、オプションのソートキーを指定できます。インデックスキースキーマは、テーブルスキーマとは異なるものにすることができます。シンプルなプライマリキー (パーティションキー) のあるテーブルを作成、および複合プライマリキー (パーティションキーおよびソートキー) のある グローバルセカンダリインデックス を作成でき、その逆も可能です。インデックスキー属性は、はベーステーブルからの任意の最上位 StringNumber、または Binary 属性で構成できます。その他のスカラー型、ドキュメント型、およびセット型は許可されません。

必要な場合、他のベーステーブル属性をインデックスに射影できます。インデックスのクエリを行うと、DynamoDB ではこれらの射影された属性を効率的に取り出すことができます。ただし、グローバルセカンダリインデックス のクエリでは、ベーステーブルから属性をフェッチできません。たとえば、上記の図に示すように、GameTitleIndex にクエリを実行した場合、クエリは TopScore 以外の非キー属性にアクセスすることはできません (キー属性 GameTitleUserId は自動的に射影されます)。

DynamoDB テーブルでは、各キー値は一意である必要があります。ただし、グローバルセカンダリインデックス のキー値は一意である必要はありません。たとえば、Comet Quest という名前のゲームが特に難しく、多くの新しいユーザーが試しても、ゼロを上回るスコアを獲得することができないとします。以下にこれを表すいくつかのデータを示します。

UserId GameTitle TopScore
123 Comet Quest 0
201 Comet Quest 0
301 Comet Quest 0

このデータが GameScores 表、 DynamoDB にプロパゲート GameTitleIndex。 その後、Comet Questを使用してインデックスに GameTitle および0は TopScore、以下のデータが返されます。


                タイトル、最上位スコア、およびユーザー ID のリストを含むテーブル。

指定したキー値を持つ項目だけがレスポンスに表示されます。その一連のデータ内では、項目は特定の順に並んでいません。

グローバルセカンダリインデックス は、キー属性が実際に存在するデータ項目のみを追跡します。たとえば、別の新しい項目を GameScores テーブルに追加し、必須のプライマリキー属性だけを指定したとします。

UserId GameTitle
400 USD Comet Quest

なぜなら、 TopScore 属性、 DynamoDB は、この項目をにプロパゲートしません GameTitleIndex。 そのため、 GameScores Comet Questの全アイテムについて、以下の4つのアイテムが手に入ります。


                4 つのタイトル、最上位スコア、およびユーザー ID のリストを含むテーブル。

GameTitleIndex に対して同様のクエリを実行すると、4 つではなく 3 つの項目が返されます。これは、TopScore が存在しない項目はインデックスに反映されないためです。


                3 つのタイトル、最上位スコア、およびユーザー ID のリストを含むテーブル。

Attribute Projections

射影は、テーブルからセカンダリインデックスにコピーされる属性セットです。テーブルのパーティションキーとソートキーは必ずインデックスに射影されます。アプリケーションのクエリ要件をサポートするために、他の属性を射影することができます。インデックスのクエリを行うと、Amazon DynamoDB は射影内の属性に、それらの属性が独立したテーブル内にあるかのようにアクセスできます。

セカンダリインデックス を作成する場合は、インデックスに射影される属性を指定する必要があります。DynamoDB にはこのための 3 つのオプションが用意されています。

  • KEYS_ONLY – インデックスの各項目は、テーブルのパーティションキーとソートキー値、およびインデックスキー値のみで構成されます。KEYS_ONLY オプションを使用すると、セカンダリインデックス は最小になります。

  • INCLUDEKEYS_ONLY の属性に加えて、セカンダリインデックス にその他の指定した非キー属性が含まれます。

  • ALL – セカンダリインデックス にソーステーブルのすべての属性が含まれます。テーブルの全データがインデックスで複製されるため、ALL の射影により、セカンダリインデックス は最大になります。

前の図では、 GameTitleIndex には、1 つの投影アトリビュートのみがあります。UserId。 そのため、アプリケーションは UserId 各ゲームのトップスコアラーの GameTitle および TopScore クエリでは、上位スコアラーの勝利と敗北の最大比率を効率的に決定することはできません。そのためには、基本テーブルで追加のクエリを実行して、各トップスコアラーの勝敗を取得する必要があります。このデータに対するクエリをサポートする、より効率的な方法は、次の図に示すように、これらの属性をベーステーブルからグローバルセカンダリインデックスに射影する方法です。

非キー属性 WinsLosses がインデックスに射影されるので、アプリケーションは、任意のゲーム、またはゲームとユーザー ID の任意の組み合わせに対して、勝敗の比率を特定できます。

グローバルセカンダリインデックス に射影する属性を選択する場合には、プロビジョニングされるスループットコストとストレージコストのトレードオフを考慮する必要があります。

  • If you need to access just a few attributes with the lowest possible latency, consider projecting only those attributes into a グローバルセカンダリインデックス. The smaller the index, the less that it costs to store it, and the less your write costs are.

  • If your application frequently accesses some non-key attributes, you should consider projecting those attributes into a グローバルセカンダリインデックス. The additional storage costs for the グローバルセカンダリインデックス offset the cost of performing frequent table scans.

  • If you need to access most of the non-key attributes on a frequent basis, you can project these attributes—or even the entire base table— into a グローバルセカンダリインデックス. This gives you maximum flexibility. However, your storage cost would increase, or even double.

  • If your application needs to query a table infrequently, but must perform many writes or updates against the data in the table, consider projecting KEYS_ONLY. The グローバルセカンダリインデックス would be of minimal size, but would still be available when needed for query activity.

Reading Data from a グローバルセカンダリインデックス

次の項目から項目を取得できます。 グローバルセカンダリインデックス 使用 Query および Scan 操作。は、 GetItem および GetBatchItem 操作は、 グローバルセカンダリインデックス.

Querying a グローバルセカンダリインデックス

Query オペレーションを使用して、グローバルセカンダリインデックス の 1 つ以上の項目にアクセスすることができます。クエリでは、使用するベーステーブル名とインデックス名、クエリ結果で返される属性、および適用するクエリ条件を指定する必要があります。DynamoDB で返される結果は、昇順にも降順にもすることができます。

順位表アプリケーションのゲームデータをリクエストする Query から返される次のデータについて考えます。

{ "TableName": "GameScores", "IndexName": "GameTitleIndex", "KeyConditionExpression": "GameTitle = :v_title", "ExpressionAttributeValues": { ":v_title": {"S": "Meteor Blasters"} }, "ProjectionExpression": "UserId, TopScore", "ScanIndexForward": false }

このクエリでは次のようになっています。

  • DynamoDB accesses GameTitleIndex, using the GameTitle partition key to locate the index items for Meteor Blasters. All of the index items with this key are stored adjacent to each other for rapid retrieval.

  • Within this game, DynamoDB uses the index to access all of the user IDs and top scores for this game.

  • The results are returned, sorted in descending order because the ScanIndexForward parameter is set to false.

Scanning a グローバルセカンダリインデックス

Scan オペレーションを使用して、グローバルセカンダリインデックス からすべてのデータを取得できます。リクエストにはベーステーブル名とインデックス名を指定する必要があります。Scan では、DynamoDB はインデックスのすべてのデータを読み取り、それをアプリケーションに返します。また、データの一部のみを返し、残りのデータを破棄するようにリクエストすることもできます。これを行うには、FilterExpression オペレーションの Scan パラメータを使用します。詳細については、「Scan のフィルタ式」を参照してください。

Data Synchronization Between Tables and Global Secondary Indexes

DynamoDB は、各グローバルセカンダリインデックスをそのベーステーブルと自動的に同期します。アプリケーションがテーブルに項目を書き込むか、削除すると、そのテーブルのすべての グローバルセカンダリインデックス は、結果整合性のあるモデルを使用して、非同期で更新されます。アプリケーションがインデックスに直接書き込むことはありません。ただし、DynamoDB でこれらのインデックスがどのように維持されるかを理解することは重要です。

グローバルセカンダリーインデックスは、基本テーブルから読み取り/書き込みキャパシティーモードを継承します。詳細については、「読み取り/書き込みキャパシティーモードの変更時の考慮事項」を参照してください。

グローバルセカンダリインデックスを作成するときは、1 つ以上のインデックスキー属性およびそれらのデータ型を指定します。つまり、ベーステーブルに項目を書き込むとき、それらの属性のデータ型が、インデックスキースキーマのデータ型に一致する必要があります。GameTitleIndex の場合、インデックス内の GameTitle パーティションキーは、String データ型として定義されています。は、 TopScore インデックスのソートキーはタイプです Number。 アイテムを追加しようとすると、 GameScores 表に入力して、いずれかの別のデータ型を指定します。 GameTitle または TopScore、 DynamoDB は、 ValidationException データタイプが一致しないため。

テーブルに項目を入力するか、削除すると、そのテーブルのグローバルセカンダリインデックスは、結果整合性のある方法で更新されます。テーブルデータへの変更は、通常は、瞬時にグローバルセカンダリインデックスに伝達されます。ただし、万が一障害が発生した場合は、長い伝達遅延が発生することがあります。このため、アプリケーションでは、グローバルセカンダリインデックス に対するクエリによって、最新でない結果が返される状況を予期し、それに対応する必要があります。

テーブルに項目を書き込む場合には、グローバルセカンダリインデックスソートキーに対して属性を指定する必要はありません。GameTitleIndex を例にとると、GameScores テーブルに新しい項目を書き込むために、TopScore 属性に値を指定する必要はありません。その場合、DynamoDB はこの特定の項目のインデックスにデータを書き込むことはありません。

多数のグローバルセカンダリインデックスがあるテーブルは、インデックス数が少ないテーブルに比べて書き込みアクティビティに多くのコストを要します。詳細については、「Provisioned Throughput Considerations for Global Secondary Indexes」を参照してください。

Provisioned Throughput Considerations for Global Secondary Indexes

プロビジョニングモードのテーブルで グローバルセカンダリインデックス を作成するときには、そのインデックスに対して予想されるワークロードに応じた読み込みおよび書き込みキャパシティーユニットを指定する必要があります。グローバルセカンダリインデックスのプロビジョニングされたスループット設定は、そのベーステーブルの設定から独立しています。グローバルセカンダリインデックス に対する Query オペレーションでは、ベーステーブルではなく、インデックスから読み込みキャパシティーユニットを消費します。テーブルで項目を入力、更新または削除すると、そのテーブルのグローバルセカンダリインデックスも更新されます。これらのインデックス更新は、ベーステーブルからではなく、インデックスから書き込みキャパシティーユニットを消費します。

たとえば、グローバルセカンダリインデックス に対して Query を実行し、そのプロビジョニングされた読み込みキャパシティーを超えた場合、リクエストは調整されます。多量の書き込みアクティビティをテーブルに対して実行するときに、そのテーブルの グローバルセカンダリインデックス に十分な書き込みキャパシティーがない場合、そのテーブルに対する書き込みアクティビティは調整されます。

注記

スロットリングを避けるため、グローバルセカンダリインデックスのプロビジョニングされた書き込みキャパシティーは、ベーステーブルの書き込みキャパシティーと同じかそれより大きい必要があります。これは、新しい更新ではベーステーブルとグローバルセカンダリインデックスの両方に書き込むためです。

グローバルセカンダリインデックス のプロビジョニングされたスループット設定を表示するには、DescribeTable オペレーションを使用します。テーブルのすべてのグローバルセカンダリインデックスに関する詳細情報が返されます。

Read Capacity Units

グローバルセカンダリインデックスでは、結果整合性のある読み込みをサポートしており、各読み込みで、読み込みキャパシティーユニットの半分を消費します。つまり、1 回の グローバルセカンダリインデックス のクエリでは、1 読み込みキャパシティーユニットあたり最大 2 × 4 KB = 8 KB を取り出すことができます。

グローバルセカンダリインデックス のクエリの場合、DynamoDB は、プロビジョニングされた読み込みアクティビティを、テーブルに対するクエリと同じ方法で計算します。唯一の違いは、ベーステーブル内の項目のサイズではなくインデックスエントリのサイズに基づいて計算が行われることです。読み込みキャパシティーユニットの数は、返されたすべての項目について射影されたすべての属性のサイズの合計です。結果は、次の 4 KB 境界まで切り上げられます。DynamoDB がプロビジョニング済みスループットの利用率を計算する方法の詳細については、「DynamoDB のプロビジョニングされたキャパシティーテーブルの設定の管理」を参照してください。

Query オペレーションによって返される結果の最大サイズは 1 MB です。これには、返されるすべての項目にわたる、すべての属性の名前と値のサイズが含まれます。

たとえば、各項目に 2000 バイトのデータが格納されている グローバルセカンダリインデックス があるとします。このインデックスに対して Query を実行したらクエリが 8 項目戻したとします。一致する項目の合計サイズは、2000 バイト × 8 項目 = 16,000 バイトです。これは、最も近い 4 KB 境界に切り上げられます。グローバルセカンダリインデックス のクエリは結果整合性があるので、合計コストは、0.5 × (16 KB/4 KB)、つまり、2 読み込みキャパシティーユニットです。

Write Capacity Units

テーブルの項目が追加、更新、または削除されたときに、グローバルセカンダリインデックス がこの影響を受ける場合、グローバルセカンダリインデックス は、そのオペレーションに対してプロビジョニングされた書き込みキャパシティーユニットを消費します。書き込み用にプロビジョニングされたスループットの合計コストは、ベーステーブルに対する書き込みと、グローバルセカンダリインデックスの更新で消費された書き込みキャパシティーユニットの合計になります。テーブルへの書き込みには、グローバルセカンダリインデックス の更新は必要ないので、インデックスから消費される書き込みキャパシティーはありません。

テーブルへの書き込みに成功するように、テーブルとそのすべてのグローバルセカンダリインデックスに対するプロビジョニングされたスループット設定は、書き込みに対応できるだけの十分な書き込みキャパシティーを備えている必要があります。十分でない場合、書き込みが調整されます。

グローバルセカンダリインデックス に項目を書き込むコストは、いくつかの要因に左右されます。

  • If you write a new item to the table that defines an indexed attribute, or you update an existing item to define a previously undefined indexed attribute, one write operation is required to put the item into the index.

  • If an update to the table changes the value of an indexed key attribute (from A to B), two writes are required, one to delete the previous item from the index and another write to put the new item into the index. 

  • If an item was present in the index, but a write to the table caused the indexed attribute to be deleted, one write is required to delete the old item projection from the index.

  • If an item is not present in the index before or after the item is updated, there is no additional write cost for the index.

  • If an update to the table only changes the value of projected attributes in the index key schema, but does not change the value of any indexed key attribute, one write is required to update the values of the projected attributes into the index.

これらすべての要因は、インデックス内の各項目のサイズが 1 KB 以下であるという前提で書き込みキャパシティーユニット数を算出します。インデックスエントリがそれよりも大きい場合は、書き込みキャパシティーユニットを追加する必要があります。クエリが返す必要がある属性を特定し、それらの属性だけをインデックスに射影することで、書き込みコストは最小になります。

Storage Considerations for Global Secondary Indexes

アプリケーションがテーブルに項目を書き込むと、DynamoDB では正しい属性のサブセットが、それらの属性が表示されるグローバルセカンダリインデックスに自動的にコピーされます。AWS アカウントでは、テーブル内の項目のストレージと、そのベーステーブルのグローバルセカンダリインデックスにある属性のストレージに対して課金されます。

インデックス項目が使用するスペースの量は、次の量の合計になります。

  • The size in bytes of the base table primary key (partition key and sort key)

  • The size in bytes of the index key attribute

  • The size in bytes of the projected attributes (if any)

  • 100 bytes of overhead per index item

グローバルセカンダリインデックス のストレージ要件の見積もりは、インデックス内の 1 項目の平均サイズの見積もり値に、ベーステーブル内の グローバルセカンダリインデックス キー属性を持つ項目の数を掛けて算出します。

特定の属性が定義されていない項目がテーブルに含まれていて、その属性がインデックスパーティションキーまたはソートキーとして定義されている場合、DynamoDB はその項目のデータをインデックスに書き込みません。