メニュー
Amazon DynamoDB
開発者ガイド (API Version 2012-08-10)

クエリおよびスキャンの使用

Amazon DynamoDB では、プライマリキーを使用した項目へのアクセスに加えて、データの検索用に Query および Scan という 2 つのオペレーションも用意されています。

ヒント

テーブルのクエリと同じ方法で セカンダリインデックス のクエリまたはスキャンを実行できます。これを行うには、Query または Scan に、パラメーターとして IndexName および TableName を指定する必要があります。詳細については、「セカンダリインデックスを使用したデータアクセス性の向上」を参照してください。

ベストプラクティスについては、クエリおよびスキャンのガイドライン を参照してください。

Query

Query オペレーションでは、プライマリキーの属性値を使用してテーブルまたは セカンダリインデックス の項目を検索します。パーティションキーの名前と検索対象の値を指定する必要があります。必要に応じて、ソートキーの名前と値を指定し、比較演算子を使用して、検索結果をさらに絞り込むことができます。デフォルトでは、Query オペレーションは、指定したプライマリキーを持つ項目のすべてのデータ属性を返します。ただし、ProjectionExpression パラメーターを使用して、Query オペレーションがすべての属性ではなく一部の属性のみを返すようにすることもできます。

Query オペレーションでは、KeyConditionExpression パラメータを使用してテーブルまたはインデックスから読み込む項目を決定します。等価条件としてパーティションキーの名前と値を指定する必要があります。オプションで、ソートキーに 2 番目の条件を指定できます (存在する場合)。ソートキーの条件では、次の比較演算子の 1 つを使用する必要があります。

  • a = b - 属性 a が値 b と等しい場合、true

  • a < b - ab より小さい場合、true

  • a <= b - ab 以下である場合、true

  • a > b - ab より大きい場合、true

  • a >= b - ab 以上である場合、true

  • a BETWEEN b AND c - ab 以上で、c 以下である場合、true。

次の関数もサポートされます。

  • begins_with (a, substr) - 属性の値 a が特定のサブ文字列から始まる場合、true。

キー条件式のいくつかの例を次に示します。これらの式では、実際の値の代わりにプレースホルダー(:name:subj など)を使用しています。詳細については、「式の属性名」および「式の属性値」を参照してください。

  • Thread テーブルに対して、特定の ForumName (パーティションキー) についてのクエリを実行します。その ForumName の値を持つすべての項目はクエリによって読み込まれます。これはソートキー (Subject) が KeyConditionExpression に含まれないためです。

    ForumName = :name

  • Thread に対して、特定の ForumName (パーティションキー) についてのクエリを実行しますが、今回は指定の Subject (ソートキー) を持つ項目のみを返します。

    Forum = :name and Subject = :subj

  • Reply テーブルに対して、特定の Id (パーティションキー) についてのクエリを実行しますが、ReplyDateTime (ソートキー) が特定の文字で始まる項目のみを返します。

    Id = :id and begins_with(ReplyDateTime, :dt)

最初の文字が a-z または A-Z であり、2 番目の文字(ある場合)が a-zA-Z、または 0-9 である場合は、キー条件式で任意の属性値を使用できます。さらに、属性名は DynamoDB の予約語ではない必要があります(フィールドの一覧については、「DynamoDB の予約語」を参照してください)。属性名がこれらの要件を満たさない場合は、式の属性名をプレースホルダーとして定義する必要があります。詳細については、「式の属性名」を参照してください。

特定のパーティションキー値を持つ項目は、DynamoDB によって、ソートキーの値で並べ替えられた順序で近くに配置されて保存されます。Query オペレーションでは、DynamoDB は並べ替えられた順序で項目を取得し、KeyConditionExpression や存在する任意の FilterExpression を使用して項目を処理します。その後、Query の結果がクライアントに返されます。

Query オペレーションは常に結果セットを返します。一致する項目が見つからない場合、結果セットは空になります。

Query の結果は常にソートキーの値によってソートされます。ソートキーのデータ型が Number である場合は、結果が番号順で返されます。その他の場合は、UTF-8 バイトの順序で結果が返されます。デフォルトの並べ替え順序は昇順です。順序を反転させるには、ScanIndexForward パラメーターを false に設定します。

1 回の Query または Scan オペレーションで、最大 1 MB のデータを取得できます。この制限は、結果への FilterExpression の適用前に適用されます。レスポンスに LastEvaluatedKey が存在し、Null 以外の場合、結果セットをページ分割する必要があります (ページ単位の出力件数を指定 を参照)。

スキャン

Scan オペレーションは、テーブルまたは セカンダリインデックス のすべての項目を読み込みます。デフォルトでは、Scan オペレーションはテーブルまたはインデックスのすべての項目のデータ属性を返します。ProjectionExpression パラメータを使用し、Scan がすべての属性ではなく一部のみを返すようにできます。

Scan は常に結果セットを返します。一致する項目がない場合、結果セットは空になります。

1 回の Scan リクエストで、最大 1 MB のデータを取得できます。DynamoDB では、必要に応じてこのデータにフィルタ式を適用して、結果をユーザーに返す前に絞り込むことができます。(フィルターの詳細については「クエリまたはスキャンからの結果のフィルタリング」を参照)。

クエリまたはスキャンからの結果のフィルタリング

Query または Scan オペレーションでは、必要に応じてフィルタ式を指定して、返された結果を絞り込むことができます。フィルタ式では、データに条件を適用できます。条件は、データをクエリまたはスキャンした後、ユーザーに返す前に適用されます。条件を満たす項目のみが返されます。

フィルタ式のいくつかの例を次に示します。これらの式では、実際の値の代わりにプレースホルダー(:num:name など)を使用しています。詳細については、「式の属性名」および「式の属性値」を参照してください。

  • Thread テーブルで特定の ForumName (パーティションキー) および Subject (ソートキー) に対するクエリを実行します。見つかった項目のうち、最も一般的なディスカッションスレッドだけを返します(たとえば、Views が特定の数を超えるスレッド)。

    #V > :num

    Views は DynamoDB の予約語であるため(「DynamoDB の予約語」を参照)、代わりに式の属性名を使用していることに注意してください。

  • Thread テーブルをスキャンして、特定のユーザーによって最後に投稿された項目のみを返します。

    LastPostedBy = :name

注記

FilterExpression の構文は ConditionExpression と同じです。また、FilterExpression は、ConditionExpression と同じコンパレータ、関数、および論理演算子を使用します。

Query オペレーションの場合、パーティションキーまたはソートキーに基づいて FilterExpression を定義することはできません (これは Sort オペレーションには適用されません)。

ConditionExpression 構文の詳細については、「条件式リファレンス」を参照してください。

1 回の Query または Scan オペレーションで、最大 1 MB のデータを取得できます。この制限は、結果への任意のフィルタ式の適用前に適用されます。

クエリおよびスキャンオペレーションによって消費されるキャパシティーユニット

テーブルを作成する場合には、読み込みおよび書き込みキャパシティーユニット要件を指定します。テーブルにグローバルセカンダリインデックスを追加する場合、そのインデックスのスループット要件も指定する必要があります。

Query および Scan オペレーションは、テーブルで使用するのと同じ方法でセカンダリインデックスで使用することができます。local secondary index で Query または Scan を実行する場合、キャパシティーユニットはテーブルのプロビジョンドスループットから消費されます。ただし、これらのオペレーションをグローバルセカンダリインデックスで行うと、キャパシティーユニットは、インデックスのプロビジョニングされたスループットから消費されます。これは、グローバルセカンダリインデックス には独自のプロビジョンドスループット設定があり、テーブルのものとは別になっているためです。

オペレーションによって消費されるキャパシティーユニットを DynamoDB が計算する方法の詳細については、「キャパシティーユニットの計算」を参照してください。

注記

QueryScan のオペレーションの場合、DynamoDB では、アプリケーションに返されるデータの量ではなく項目のサイズに基づいて、消費されるプロビジョンドスループットの量が計算されます。このため、消費されるキャパシティーユニットの数は、ProjectionExpression パラメーターで属性のすべてをリクエストしても(デフォルトの動作)一部をリクエストしても、同じになります。

消費されるキャパシティーユニットの数も、FilterExpression オペレーションを指定しても指定しなくても、同じになります。

ページ単位の出力件数を指定

DynamoDB では、Query および Scan オペレーションで得られた結果のページ分割を行うことができます。ページ分割を行うことで Query および Scan の結果が分割されるため、アプリケーションでは結果の最初のページ、次に 2 番目のページというように、順次処理していくことができます。Query または Scan オペレーションによって返されるデータは、1 MB に限定されます。これは、結果セットのデータが 1 MB を超えた場合、新たに Query または Scan オペレーションを実行して次のデータを 1 MB 取得する必要があることを意味しています。

特定の属性に対するクエリまたはスキャンを実行して、一致する値の合計データが 1 MB を超える場合には、次の 1 MB のデータに対する Query または Scan リクエストを別に実行する必要があります。そのためには、前のリクエストから LastEvaluatedKey の値を取得し、次のリクエストで ExclusiveStartKey として使用します。このアプローチにより、新しいデータを 1 MB ずつインクリメントさせて段階的にクエリまたはスキャンできるようになります。

Query または Scan からの結果セット全体が処理されると、LastEvaluatedKeynull になります。これは、結果セットが完了したこと(つまり、オペレーションによってデータの「最後のページ」が処理されたこと)を意味します。

LastEvaluatedKeynull 以外の値の場合、結果セットにまだ値があることを必ずしも意味するわけではありません。結果セットの最後まで到達したことを確認できるのは、LastEvaluatedKeynull になったときだけです。

制限

DynamoDB の Query および Scan API では、Limit の値によって結果のサイズを制限できます。

リクエストでは、Limit パラメータに、DynamoDB が結果を返す前に処理する項目数を設定します。

応答では、DynamoDB は Limit の値の範囲で一致したすべての結果を返します。たとえば、Limit 値が 6 でフィルタ式のない Query リクエストまたは Scan リクエストを発行した場合、DynamoDB は、リクエストで指定されたキー条件に一致するテーブル内の最初の 6 つの項目を返します(または、フィルタのない Scan の場合はそのまま最初の 6 つの項目)。FilterExpression 値も指定した場合、DynamoDB は、フィルタ要件にも一致する最初の 6 つの中から項目を返します(返される結果の数は 6 以下です)。

Query または Scan オペレーションでは、テーブル内で一致する項目の一部が返されるときは、DynamoDB によって LastEvaluatedKey の値が返される場合があります。一致する項目の総数を取得するには、前のリクエストから LastEvaluatedKey の値を取得し、次のリクエストで ExclusiveStartKey の値として使用します。DynamoDB から LastEvaluatedKey の値が返されなくなるまで、この処理を繰り返します。

応答での項目のカウント

Query または Scan オペレーションからの応答には、条件に一致する項目に加えて次の要素が含まれます。

  • ScannedCount — フィルタ式が結果に適用される前にクエリまたはスキャンされた項目の数。

  • Count — 応答で返された項目の数。

FilterExpression を使用しない場合、ScannedCountCount は同じ値を持ちます。

1000 項目がある TestTable というテーブルがあり、各項目のサイズは正確に 250 バイトであるとします。このテーブルに Scan (フィルタなし) を実行する場合、ScannedCountCount は同じ値 (1000) を持ちます。ここで、FilterExpression を追加し、300 項目のみが返されるとします。DynamoDB はそれでも 1000 個の項目を TestTable からすべて読み込みますが、条件に一致する 300 項目を除くこれらのすべての結果を破棄します。この場合、ScannedCount は 1000 になりますが、Count は 300 になります。

結果セットのサイズが 1 MB を超えた場合、ScannedCount および Count は、合計項目数の一部の数のみを表します。TestTable に 100 万の項目があり、各項目のサイズが 250 KB であるとします。この場合、テーブル全体をスキャンするために、複数の Scan リクエストを実行する必要があります。(詳細については、「ページ単位の出力件数を指定」を参照してください)。各応答には、特定の Scan リクエストによって処理された項目の ScannedCount および Count が含まれます。すべての Scan リクエストの合計を取得するには、ScannedCount および Count の実行中の集計を維持することができます。

読み込み整合性

クエリの読み込み整合性

Query の結果は結果整合性のある読み込みですが、必要に応じて強力な整合性のある読み込みをリクエストすることもできます。結果整合性のある読み込みには、最近完了した PutItem または UpdateItem オペレーションの結果が反映されない可能性があります。詳細については、「読み込み整合性」を参照してください。

スキャンの読み込み整合性

Scan リクエストを発行すると、DynamoDB は結果的に整合性のある読み込みを使用します。つまり、テーブルでスキャンの実行直前に加えられたデータの変更は、スキャン結果に含まれない可能性があります。データの整合性のあるコピーが必要な場合は、Scan が開始する時間に、ConsistentRead パラメーターを true に設定できます。これにより、Scan が開始する前に完了した書き込みオペレーションがすべて Scan 応答に含められます。これは、 DynamoDB ストリーム と同時に使用すると、テーブルのバックアップまたはレプリケーションシナリオで役立ちます。最初に、テーブル内のデータの整合性のあるコピーを取得するため、ConsistentRead を true に設定して Scan を使用します。Scan の実行中、DynamoDB ストリーム はテーブルで発生した追加の書き込みアクティビティをすべて記録します。Scan が完了したら、ストリームからテーブルへの書き込みアクティビティを適用できます。

ConsistentRead を true に設定した Scan オペレーションでは、ConsistentRead をデフォルト値 (false) のままにした場合と比較して、2 倍の読み込みキャパシティーユニットが使用されます。

クエリおよびスキャンのパフォーマンス

一般的に、Query オペレーションは Scan オペレーションよりも効率的です。

Scan オペレーションでは常にテーブル全体またはセカンダリインデックスがスキャンされ、目的の結果を得るために値にフィルタが適用され、基本的に結果セットからデータを削除するステップが追加されます。フィルタによって多数の結果が除外されるようなサイズの大きいテーブルまたはインデックスでは、可能な限り Scan オペレーションを使用しないことをお勧めします。また、テーブルやインデックスが大きくなるに従って、Scan オペレーションは低速になります。Scan オペレーションでは、リクエストした値に対するすべての項目が調べられるため、サイズの大きいテーブルまたはインデックスでは、プロビジョニングされたスループットが 1 回のオペレーションで枯渇する可能性があります。高速な応答時間を得るには、アプリケーションが Scan ではなく Query を使用できるようにテーブルとインデックスを設計します(テーブルの場合は、GetItem および BatchGetItem API の使用を検討することもできます)。

または、Scan オペレーションを使用してもリクエスト率に対する影響が最小になるように、アプリケーションを設計します。詳細については、「クエリおよびスキャンのガイドライン」を参照してください。

Query オペレーションは、指定した一連のキー条件を満たす特定範囲のキーを検索します。フィルタ式を指定した場合、DynamoDB は結果セットからデータを削除する追加の手順を実行する必要があります。Query オペレーションでは、次のいずれかのイベントが発生するまで、指定された複合プライマリキーまたは一定範囲のキーが検索されます。

  • 結果セットが枯渇する。

  • 取り出した項目数が、指定した Limit パラメータの値に達する。

  • 取り出したデータの量が、結果セットの最大サイズ制限 1 MB に達する。

Query のパフォーマンスは、テーブルまたはセカンダリインデックス内のプライマリキーの全体数ではなく、取り出されたデータの量によって決まります。クエリのパフォーマンスは、Query オペレーションのパラメータ(および結果的に一致したキーの数)によって決まります。たとえば、1 つのパーティションキー値に対するソートキー値の数が少ないテーブルに対するクエリよりも、1 つのパーティションキー値に対する多量のソートキー値が含まれる別のテーブルに対するクエリのほうが、最初のテーブルで一致するキーの数が 2 番目のテーブルよりも少ない場合には効率的です。どちらのテーブルでも、プライマリキーの合計数によって、Query オペレーションの効率性が決まることはありません。フィルタ式は Query オペレーションの効率に影響を与えることがあります。フィルタに一致しない項目を結果セットから削除する必要があるためです。フィルタによって多数の結果が除外されるようなサイズの大きいテーブルまたはセカンダリインデックスでは、可能な限り Query オペレーションを使用しないことをお勧めします。

特定のパーティションキー値にサイズの大きいソートキー値のセットがあり、1 つの Query リクエストでは結果を取り出せない場合には、ExclusiveStartKey 継続パラメーターによって、最後に取り出した項目から新しいクエリリクエストを送信できます。すでに取り出されたデータを再処理する必要はありません。

並列スキャン

デフォルトでは、Scan オペレーションはデータを連続的に処理します。DynamoDB は 1 MB の増分でアプリケーションにデータを返し、アプリケーションは追加の Scan オペレーションを実行して、次の 1 MB 分のデータを取り出します。

スキャンされるテーブルまたはインデックスが大きいほど、Scan の完了に要する時間は長くなります。さらに、シーケンシャルな Scan では、プロビジョニングされた読み込みスループットキャパシティーが完全に利用されない場合があります。DynamoDB がサイズの大きいテーブルのデータを複数の物理パーティションに分散しても、Scan オペレーションでは一度に 1 つのパーティションしか読み込むことができません。そのため Scan のスループットは、単一のパーティションの最大スループットによって制限されます。

これらの問題に対処するために、Scan オペレーションではテーブルまたはセカンダリインデックスを複数のセグメントに論理的に分割して、複数のアプリケーションワーカーがセグメントに対する並列スキャンを行うことができます。各ワーカーは、スレッド(マルチスレッドをサポートするプログラミング言語を使用)またはオペレーティングシステムのプロセスにすることができます。並列スキャンを実行するには、各ワーカーが次のパラメータを使用して、別個に Scan リクエストを行います。

  • Segment — 特定のワーカーがスキャンするセグメント。各ワーカーは Segment にそれぞれ異なる値を指定します。

  • TotalSegments — 並列スキャンの対象となるセグメントの合計数。この値は、アプリケーションで使用されるワーカーの数と同じでなければなりません。

次の図は、マルチスレッドアプリケーションが 3 段階の並列処理で実行する並列 Scan を示しています。

この図では、アプリケーションが 3 つのスレッドをスポーンして、各スレッドに番号を割り当てています(セグメントはゼロベースであるため、最初の数字は必ず 0 になります)。各スレッドは Scan リクエストを発行し、Segment を指定された数値に設定して、TotalSegments を 3 に設定します。各スレッドは指定されたセグメントをスキャンし、一度に 1 MB のデータを取り出し、アプリケーションのメインスレッドにデータを返します。

Segment および TotalSegments の値は個々の Scan リクエストに適用され、また異なる値をいつでも使用できます。これらの値、および使用するワーカー数を決定するには、アプリケーションのパフォーマンスが最高になるまで実験を行う必要があるかもしれません。

注記

多数のワーカーで行う並列スキャンでは、スキャンされるテーブルまたはインデックスのためにプロビジョニングされたスループットがすぐにすべて使用されます。テーブルまたはインデックスでも他のアプリケーションからの重い読み込みや書き込みが発生させる場合は、このようなスキャンは避けるのが最善です。

リクエストごとに返されるデータの量を制御するには、Limit パラメータを使用します。それによって、1 つのワーカーがプロビジョニングされたスループットを使い果たして、他のワーカーが制約を受ける状況が避けられます。詳細については、「読み込みアクティビティの急激な増大の回避」の「ページサイズを小さくする」を参照してください。