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

クエリとスキャンデータのベストプラクティス

このセクションでは、Query および Scanオペレーションのベストプラクティスを示します。

スキャンのパフォーマンスに関する考慮事項

一般に、Scan オペレーションよりも、DynamoDB の他のオペレーションのほうが効率的です。

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

または、Scan オペレーションを使用してもリクエスト率に対する影響が最小になるように、アプリケーションを設計します。

読み込みアクティビティの急激な増大の回避

テーブルを作成する場合には、読み込みおよび書き込みキャパシティーユニット要件を設定します。読み込みの場合、キャパシティーユニットは、強力な整合性のある 1 秒あたり 4 KB のデータ読み込みリクエスト数として表されます。結果整合性のある読み込みの場合、読み込みキャパシティーユニットは、1 秒あたり 2 回の 4 KB の読み込みリクエストになります。Scan オペレーションでは結果整合性のある読み込みがデフォルトで実行され、最大 1 MB(1 ページ)のデータが返されます。したがって、1 回の Scan リクエストでは、(1 MB のページサイズ/ 4 KB の項目サイズ)/ 2(結果整合性のある読み込み)= 128 の読み込みオペレーションが実行されます。もし、代わりに強い整合性のある読み込みをリクエストすると、Scan オペレーションはプロビジョニングされたスループットを 2 倍消費します(256 の読み込みオペレーション)。

これはテーブルに設定済みの読み込みキャパシティーに比べて、使用量が急激に増大することを意味します。このようにスキャンが使用するキャパシティーユニットが増大すると、同じテーブルに対するその他の重要なリクエストがキャパシティーユニットを使用する妨げになります。その結果、それらのリクエストについて ProvisionedThroughputExceeded 例外が発生する可能性があります。

問題なのは、Scan が使用するキャパシティーユニットの急激な増大だけではありません。スキャンではパーティション内で隣接する読み込み項目がリクエストされるため、スキャンによって、同じパーティションのキャパシティーユニットがすべて消費される可能性があります。つまり同じパーティションがリクエストの対象になるため、キャパシティーユニットがすべて消費され、そのパーティションに対する他のリクエストが制限されることになります。データ読み込みのリクエストを複数のパーティションに分散させれば、オペレーションによって特定のパーティションが制限されることはありません。

次の図は、Query および Scan オペレーションによるキャパシティーユニットの使用量の急激な増大の影響と、同じテーブルに対する他のリクエストに及ぼす影響を示しています。

 

大がかりな Scan オペレーションの代わりに次の手法を使用すれば、テーブルのプロビジョニングされたスループットに対するスキャンの影響を最小限に抑えることができます。

  • ページサイズを小さくする

    スキャンオペレーションではページ全体(デフォルトでは 1 MB)を読み込むため、設定するページサイズを小さくすることで、スキャンの影響を軽減させることができます。Scan オペレーションには、リクエストのページサイズの設定に使用できる Limit パラメータがあります。Query または Scan リクエストのページサイズが小さい場合は、読み込みオペレーションの数が少なくなり、各リクエストの間に間隔ができます。たとえば、各項目が 4 KB で、ページサイズを 40 項目に設定した場合に Query リクエストで使用されるのは、40 回の強力な整合性のある読み込みオペレーション、または 20 回の結果整合性のある読み込みオペレーションです。Query または Scan オペレーションのサイズが小さくなって回数が増えれば、他の重要なリクエストが制限されることなく実行されるようになります。

  • スキャンオペレーションを分離する

    DynamoDB は容易に拡張できるように設計されています。そのため、アプリケーションでは明確な目的でテーブルを作成できます。コンテンツを複数のテーブルに複製することも可能です。「ミッションクリティカル」なトラフィックを扱わないテーブルに対するスキャンを実行するとします。アプリケーションによっては、(重要なトラフィック用と記録用の)2 つのテーブル間で 1 時間ごとにトラフィックを分担することで、この負荷が処理されます。また別のアプリケーションでは、すべての書き込みを 2 つのテーブル(「ミッションクリティカル」なテーブルと「シャドウ」テーブル)に対して行うことで処理されます。

アプリケーションのリクエストに対しプロビジョニングされたスループットを超えたことを示す応答コードが返された場合にはそのリクエストを再試行するか、UpdateTable オペレーションを使用してテーブルにプロビジョニングされたスループットを増やすようにアプリケーションを設定します。ワークロードが一時的に急増して、プロビジョニングされたレベルをスループットが超えることがある場合には、エクスポネンシャルパックオフによってリクエストを再試行します。エクスポネンシャルパックオフの実装の詳細については、「エラーの再試行とエクスポネンシャルバックオフ」を参照してください。

並列スキャンの利用

多くのアプリケーションでは、シーケンシャルスキャンよりも並列 Scan オペレーションのほうが有効です。たとえば、サイズの大きい履歴データテーブルを処理するアプリケーションでは、シーケンシャルスキャンよりも並列スキャンのほうが大幅に速く実行できます。バックグラウンドの "スイーパー" プロセスで複数のワーカースレッドを使用することで、プロダクショントラフィックに影響することなく、低いプライオリティでテーブルをスキャンできます。これらの例では、他のアプリケーションが使用するプロビジョニングされたスループットリソースが枯渇しないように、並列 Scan が使用されています。

並列スキャンは有益ですが、プロビジョニングされたスループットが多量に消費される可能性があります。並列スキャンでは、複数のワーカーがアプリケーションを使用して Scan オペレーションを同時に実行するため、テーブルにプロビジョニングされた読み込みキャパシティーが急速に消費されます。その場合は、テーブルにアクセスする必要がある他のアプリケーションが制限される可能性があります。

並列スキャンが適しているのは、次の条件に当てはまる場合です。

  • テーブルのサイズが 20 GB 以上である。

  • テーブルにプロビジョニングされている読み込みスループットが完全に使用されていない。

  • シーケンシャル Scan オペレーションでは遅すぎる。

TotalSegments の選択

TotalSegments の最適な設定は、使用するデータ、テーブルにプロビジョニングされるスループット設定、パフォーマンス要件によって異なります。最適な設定は実験を通じて明らかになる場合もあります。2 GB のデータにつき 1 セグメントなど、単純な比率から始めることをお勧めします。たとえば 30 GB のテーブルでは、TotalSegments を 15(30 GB / 2 GB)に設定できます。アプリケーションでは 15 のワーカーを使用して、各ワーカーが異なるセグメントをスキャンするようにします。

TotalSegments の値は、クライアントのリソースに基づいて選択することもできます。TotalSegments を 1~1000000 の範囲の任意の数値に設定すると、DynamoDB ではその数のセグメントをスキャンできます。たとえば、クライアントで同時に実行できるスレッド数が制限されている場合には、アプリケーションで Scan のパフォーマンスが最高になるまで、TotalSegments を徐々に増やすことができます。

プロビジョニングされたスループットの使用率を最適にするには、並列スキャンをモニタリングするとともに、他のアプリケーションが使用するリソースが枯渇しないようにする必要があります。プロビジョニングされたスループットをすべて消費しないうちに Scan リクエストが制限される場合には、TotalSegments の値を増やします。Scan リクエストによって、プロビジョニングされたスループットが必要以上に消費される場合には、TotalSegments の値を減らします。