「翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。」
DynamoDB のグローバルセカンダリインデックスの使用
アプリケーションによっては、さまざまな属性をクエリ基準に使用して、いろいろな種類のクエリを実行する必要があります。このような要件に対応するために、1 つ以上のグローバルセカンダリインデックスを作成して、Amazon DynamoDB でそのインデックスに対して Query
リクエストを発行できます。
トピック
シナリオ: グローバルセカンダリインデックスの使用
たとえば、GameScores
という名前のテーブルがあり、モバイルゲームアプリケーションのユーザーとスコアを記録しているとします。GameScores
の各項目は、パーティションキー (UserId
) およびソートキー (GameTitle
) で特定されます。次の図は、テーブル内の項目の構成を示しています。一部表示されていない属性もあります。

ここで、各ゲームの最高スコアを表示する順位表アプリケーションを作成すると仮定します。キー属性 (UserId
と GameTitle
) を指定したクエリは非常に効率的です。ただし、アプリケーションが GameTitle
だけに基づいて GameScores
からデータを取り出す必要がある場合、Scan
オペレーションを使用する必要があります。テーブルに追加される項目が増えるにつれ、すべてのデータのスキャンは低速で非効率的になります。このため、次のような質問に答えることが難しくなります。
-
ゲーム Meteor Blasters で記録された最高スコアはいくつですか?
-
Galaxy Invaders で最高スコアを獲得したユーザーは誰ですか?
-
勝敗の最も高い比率は何ですか?
非キー属性に対するクエリの速度を上げるために、グローバルセカンダリインデックス を作成できます。グローバルセカンダリインデックスには、ベーステーブルからの属性の一部が格納されますが、テーブルのプライマリキーとは異なるプライマリキーによって構成されます。インデックスキーは、テーブルからのキー属性を持つ必要がありません。また、テーブルと同じキースキーマを使用する必要もありません。
たとえば、パーティションキーとして グローバルセカンダリインデックス、ソートキーとして GameTitleIndex
を使用して、GameTitle
という名前の TopScore
を作成できます。 ベーステーブルのプライマリキー属性は常にインデックスに射影されるので、UserId
属性も存在します。次の図は、GameTitleIndex
インデックスを示しています。

これで、GameTitleIndex
に対してクエリを実行し、Meteor Blasters のスコアを簡単に入手できるようになります。結果はソートキーの値 TopScore
によって順序付けられます。 パラメータを false に設定した場合、結果は降順で返されるため、最高スコアが最初に返されます。ScanIndexForward
すべてのグローバルセカンダリインデックスには、パーティションキーが必要で、オプションのソートキーを指定できます。インデックスキースキーマは、テーブルスキーマとは異なるものにすることができます。シンプルなプライマリキー
(パーティションキー) を持つテーブルを作成し、複合プライマリキー (パーティションキーおよびソートキー) を持つ グローバルセカンダリインデックス を作成したり、—その逆を作成したりできます。インデックスキー属性は、はベーステーブルからの任意の最上位
String
、Number
、または Binary
属性で構成できます。その他のスカラー型、ドキュメント型、およびセット型は許可されません。
必要な場合、他のベーステーブル属性をインデックスに射影できます。インデックスのクエリを行うと、DynamoDB ではこれらの射影された属性を効率的に取り出すことができます。ただし、グローバルセカンダリインデックス
のクエリでは、ベーステーブルから属性をフェッチできません。たとえば、上記の図に示すように、GameTitleIndex
にクエリを実行した場合、クエリは TopScore
以外の非キー属性にアクセスすることはできません (キー属性 GameTitle
と UserId
は自動的に射影されます)。
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

指定したキー値を持つ項目だけがレスポンスに表示されます。その一連のデータ内では、項目は特定の順に並んでいません。
グローバルセカンダリインデックス は、キー属性が実際に存在するデータ項目のみを追跡します。たとえば、別の新しい項目を GameScores
テーブルに追加し、必須のプライマリキー属性だけを指定したとします。
UserId | GameTitle |
---|---|
400 | Comet Quest |
属性を指定していないため、TopScore
はこの項目を DynamoDB に反映しません。GameTitleIndex
このため、すべての Comet Quest 項目に対して GameScores
をクエリした場合、次の 4 つの項目が返されます。

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

属性の射影
射影は、テーブルからセカンダリインデックスにコピーされる属性セットです。テーブルのパーティションキーとソートキーは必ずインデックスに射影されます。アプリケーションのクエリ要件をサポートするために、他の属性を射影することができます。インデックスのクエリを行うと、Amazon DynamoDB は射影内の属性に、それらの属性が独立したテーブル内にあるかのようにアクセスできます。
セカンダリインデックス を作成する場合は、インデックスに射影される属性を指定する必要があります。DynamoDB にはこのための 3 つのオプションが用意されています。
-
KEYS_ONLY – インデックスの各項目は、テーブルのパーティションキーとソートキー値、およびインデックスキー値のみで構成されます。
KEYS_ONLY
オプションを使用すると、セカンダリインデックス は最小になります。 -
INCLUDE –
KEYS_ONLY
の属性に加えて、セカンダリインデックス にその他の指定した非キー属性が含まれます。 -
ALL – セカンダリインデックス にソーステーブルのすべての属性が含まれます。テーブルの全データがインデックスで複製されるため、
ALL
の射影により、セカンダリインデックス は最大になります。
前の図では、GameTitleIndex
には 1 つの射影された属性のみがあります。UserId
。 そのため、アプリケーションはクエリで UserId
および GameTitle
を使用して各ゲームのトップスコアラーの TopScore
を効率的に判断できますが、トップスコアラーの勝敗の最も高い比率は効率的に判断できません。そのためには、基本テーブルで追加のクエリを実行して、各トップスコアラーの勝敗を取得する必要があります。このデータに対するクエリをサポートする、より効率的な方法は、次の図に示すように、これらの属性をベーステーブルからグローバルセカンダリインデックスに射影する方法です。

非キー属性 Wins
と Losses
がインデックスに射影されるので、アプリケーションは、任意のゲーム、またはゲームとユーザー ID の任意の組み合わせに対して、勝敗の比率を特定できます。
グローバルセカンダリインデックス に射影する属性を選択する場合には、プロビジョニングされるスループットコストとストレージコストのトレードオフを考慮する必要があります。
-
ごく一部の属性だけに最小のレイテンシーでアクセスする必要がある場合は、それらの属性だけを グローバルセカンダリインデックス に射影することを検討してください。インデックスが小さいほど少ないコストで格納でき、書き込みコストも低くなります。
-
アプリケーションが非キー属性に頻繁にアクセスする場合には、それらの属性を グローバルセカンダリインデックス に射影することを検討してください。グローバルセカンダリインデックス の追加のストレージコストは、頻繁なテーブルスキャンを実行するコストを相殺します。
-
ほとんどの非キー属性に頻繁にアクセスする場合は、それらの属性 —さらにベーステーブル全体 — を グローバルセカンダリインデックス に射影することができます。これにより、最大限の柔軟性が得られます。ただし、ストレージコストは増加するか、倍になります。
-
アプリケーションでテーブルのクエリを頻繁に行う必要がなく、テーブル内のデータに対する書き込みや更新が多数になる場合は、
KEYS_ONLY
を射影することを検討してください。 のサイズは最小になりますが、アクティビティに必要なサイズは確保されます。グローバルセカンダリインデックス
からのデータの読み取りグローバルセカンダリインデックス
および グローバルセカンダリインデックス オペレーションを使用して、Query
から項目を取得できます。Scan
オペレーションと GetItem
オペレーションは、GetBatchItem
では使用できません。グローバルセカンダリインデックス
グローバルセカンダリインデックス のクエリ
Query
オペレーションを使用して、グローバルセカンダリインデックス の 1 つ以上の項目にアクセスすることができます。クエリでは、使用するベーステーブル名とインデックス名、クエリ結果で返される属性、および適用するクエリ条件を指定する必要があります。DynamoDB
で返される結果は、昇順にも降順にもすることができます。
順位表アプリケーションのゲームデータをリクエストする Query
から返される次のデータについて考えます。
{ "TableName": "GameScores", "IndexName": "GameTitleIndex", "KeyConditionExpression": "GameTitle = :v_title", "ExpressionAttributeValues": { ":v_title": {"S": "Meteor Blasters"} }, "ProjectionExpression": "UserId, TopScore", "ScanIndexForward": false }
このクエリでは次のようになっています。
-
DynamoDB は GameTitleIndex にアクセスし、GameTitle パーティションキーを使用して Meteor Blasters のインデックス項目を特定します。このキーを持つすべてのインデックス項目が、すばやく取り出せるように隣り合わせに格納されます。
-
このゲーム内で、DynamoDB はインデックスを使用して、このゲームのすべてのユーザー IDs と最高スコアにアクセスします。
-
ScanIndexForward
パラメータが false に設定されているので、結果は降順で返されます。
グローバルセカンダリインデックス のスキャン
Scan
オペレーションを使用して、グローバルセカンダリインデックス からすべてのデータを取得できます。リクエストにはベーステーブル名とインデックス名を指定する必要があります。Scan
では、DynamoDB はインデックスのすべてのデータを読み取り、それをアプリケーションに返します。また、データの一部のみを返し、残りのデータを破棄するようにリクエストすることもできます。これを行うには、FilterExpression
オペレーションの Scan
パラメータを使用します。詳細については、「Scan のフィルタ式」を参照してください。
テーブルとグローバルセカンダリインデックス間のデータ同期
DynamoDB は、各グローバルセカンダリインデックスをそのベーステーブルと自動的に同期します。アプリケーションがテーブルに項目を書き込むか、削除すると、そのテーブルのすべての グローバルセカンダリインデックス は、結果整合性のあるモデルを使用して、非同期で更新されます。アプリケーションがインデックスに直接書き込むことはありません。ただし、DynamoDB でこれらのインデックスがどのように維持されるかを理解することは重要です。
グローバルセカンダリーインデックスは、基本テーブルから読み取り/書き込みキャパシティーモードを継承します。詳細については、「読み取り/書き込みキャパシティーモードの変更時の考慮事項」を参照してください。
グローバルセカンダリインデックスを作成するときは、1 つ以上のインデックスキー属性およびそれらのデータ型を指定します。つまり、ベーステーブルに項目を書き込むとき、それらの属性のデータ型が、インデックスキースキーマのデータ型に一致する必要があります。GameTitleIndex
の場合、インデックス内の GameTitle
パーティションキーは、String
データ型として定義されています。インデックス内の TopScore
ソートキーは、Number
の型です。 テーブルに項目を追加し、GameScores
または GameTitle
に対して別のデータ型を指定する場合、データ型の不一致により TopScore
によって DynamoDB が返されます。ValidationException
テーブルに項目を入力するか、削除すると、そのテーブルのグローバルセカンダリインデックスは、結果整合性のある方法で更新されます。テーブルデータへの変更は、通常は、瞬時にグローバルセカンダリインデックスに伝達されます。ただし、万が一障害が発生した場合は、長い伝達遅延が発生することがあります。このため、アプリケーションでは、グローバルセカンダリインデックス に対するクエリによって、最新でない結果が返される状況を予期し、それに対応する必要があります。
テーブルに項目を書き込む場合には、グローバルセカンダリインデックスソートキーに対して属性を指定する必要はありません。GameTitleIndex
を例にとると、GameScores
テーブルに新しい項目を書き込むために、TopScore
属性に値を指定する必要はありません。その場合、DynamoDB はこの特定の項目のインデックスにデータを書き込むことはありません。
多数のグローバルセカンダリインデックスがあるテーブルは、インデックス数が少ないテーブルに比べて書き込みアクティビティに多くのコストを要します。詳細については、「グローバルセカンダリインデックスに対するプロビジョニング済みスループットに関する考慮事項」を参照してください。
グローバルセカンダリインデックスに対するプロビジョニング済みスループットに関する考慮事項
プロビジョニングモードのテーブルで グローバルセカンダリインデックス を作成するときには、そのインデックスに対して予想されるワークロードに応じた読み込みおよび書き込みキャパシティーユニットを指定する必要があります。グローバルセカンダリインデックスのプロビジョニングされたスループット設定は、そのベーステーブルの設定から独立しています。グローバルセカンダリインデックス
に対する Query
オペレーションでは、ベーステーブルではなく、インデックスから読み込みキャパシティーユニットを消費します。テーブルで項目を入力、更新または削除すると、そのテーブルのグローバルセカンダリインデックスも更新されます。これらのインデックス更新は、ベーステーブルからではなく、インデックスから書き込みキャパシティーユニットを消費します。
たとえば、グローバルセカンダリインデックス に対して Query
を実行し、そのプロビジョニングされた読み込みキャパシティーを超えた場合、リクエストは調整されます。多量の書き込みアクティビティをテーブルに対して実行するときに、そのテーブルの
グローバルセカンダリインデックス に十分な書き込みキャパシティーがない場合、そのテーブルに対する書き込みアクティビティは調整されます。
スロットリングを避けるため、グローバルセカンダリインデックスのプロビジョニングされた書き込みキャパシティーは、ベーステーブルの書き込みキャパシティーと同じかそれより大きい必要があります。これは、新しい更新ではベーステーブルとグローバルセカンダリインデックスの両方に書き込むためです。
グローバルセカンダリインデックス のプロビジョニングされたスループット設定を表示するには、DescribeTable
オペレーションを使用します。テーブルのすべてのグローバルセカンダリインデックスに関する詳細情報が返されます。
読み込みキャパシティーユニット
グローバルセカンダリインデックスでは、結果整合性のある読み込みをサポートしており、各読み込みで、読み込みキャパシティーユニットの半分を消費します。つまり、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 読み込みキャパシティーユニットです。
書き込みキャパシティーユニット
テーブルの項目が追加、更新、または削除されたときに、グローバルセカンダリインデックス がこの影響を受ける場合、グローバルセカンダリインデックス は、そのオペレーションに対してプロビジョニングされた書き込みキャパシティーユニットを消費します。書き込み用にプロビジョニングされたスループットの合計コストは、ベーステーブルに対する書き込みと、グローバルセカンダリインデックスの更新で消費された書き込みキャパシティーユニットの合計になります。テーブルへの書き込みには、グローバルセカンダリインデックス の更新は必要ないので、インデックスから消費される書き込みキャパシティーはありません。
テーブルへの書き込みに成功するように、テーブルとそのすべてのグローバルセカンダリインデックスに対するプロビジョニングされたスループット設定は、書き込みに対応できるだけの十分な書き込みキャパシティーを備えている必要があります。十分でない場合、書き込みが調整されます。
グローバルセカンダリインデックス に項目を書き込むコストは、いくつかの要因に左右されます。
-
インデックス付き属性が定義されたテーブルに新しい項目を書き込む場合、または既存の項目を更新して未定義のインデックス付き属性を定義する場合には、インデックスへの項目の挿入に 1 回の書き込みオペレーションが必要です。
-
テーブルに対する更新によってインデックス付きキー属性の値が(A から B に)変更された場合には、インデックスから既存の項目を削除し、インデックスに新しい項目を挿入するために、2 回の書き込みが必要です。
-
インデックス内に既存の項目があって、テーブルに対する書き込みによってインデックス付き属性が削除された場合は、インデックスから古い項目の射影を削除するために、1 回の書き込みが必要です。
-
項目の更新の前後にインデックス内に項目が存在しない場合は、インデックスで追加の書き込みコストは発生しません。
-
テーブルに対する更新によってインデックスキースキーマの射影された属性の値のみが変更され、インデックス付きキー属性の値は変更されない場合は、インデックスに射影された属性の値を更新するために、1 回の書き込みが必要です。
これらすべての要因は、インデックス内の各項目のサイズが 1 KB 以下であるという前提で書き込みキャパシティーユニット数を算出します。インデックスエントリがそれよりも大きい場合は、書き込みキャパシティーユニットを追加する必要があります。クエリが返す必要がある属性を特定し、それらの属性だけをインデックスに射影することで、書き込みコストは最小になります。
グローバルセカンダリインデックスのストレージに関する考慮事項
アプリケーションがテーブルに項目を書き込むと、DynamoDB では正しい属性のサブセットが、それらの属性が表示されるグローバルセカンダリインデックスに自動的にコピーされます。AWS アカウントでは、テーブル内の項目のストレージと、そのベーステーブルのグローバルセカンダリインデックスにある属性のストレージに対して課金されます。
インデックス項目が使用するスペースの量は、次の量の合計になります。
-
ベーステーブルのプライマリキー (パーティションキーとソートキー) のサイズのバイト数
-
インデックスキー属性のサイズのバイト数
-
射影された属性(存在する場合)のサイズのバイト数
-
インデックス項目あたり 100 bytes のオーバーヘッド
グローバルセカンダリインデックス のストレージ要件の見積もりは、インデックス内の 1 項目の平均サイズの見積もり値に、ベーステーブル内の グローバルセカンダリインデックス キー属性を持つ項目の数を掛けて算出します。
特定の属性が定義されていない項目がテーブルに含まれていて、その属性がインデックスパーティションキーまたはソートキーとして定義されている場合、DynamoDB はその項目のデータをインデックスに書き込みません。