DynamoDB の制限とクォータ:実サービスに対して検証
DynamoDB の制限には何がありますか?
アイテムは 400 KB、パーティションキーは 2,048 バイト、ソートキーは 1,024 バイトが上限です。バッチ書き込みは 25 アイテム、バッチ取得は 100 キー、 トランザクションは 100 アクションまでです。テーブルは 20 個のグローバル セカンダリインデックスと 5 個のローカルセカンダリインデックスを持てます。 このページのこれらの数値はすべて、Amazon DynamoDB に実際にリクエストを送り、 返ってきた結果から確定させたものです。
これらの数値をどう確定させたか
AWS は根拠を示さずにクォータを公開しており、それは普段は問題になりません — ある数値が設計判断の拠り所になり、それが 400,000 バイトなのか 409,600 バイトなのか、属性名を含めてカウントするのか、上限を超えたときにサービスが 正確に何を言うのかを知りたくなるまでは。
そこで実際に確かめました。下の最初の表にある制限それぞれについて、ドキュメント
に書かれた値にちょうど乗るリクエストを組み立て、実サービスの us-east-1
に送信しました。続けて、それより 1 単位だけ超えたリクエストも送信しました。
前者は受理され、後者は拒否されるはずです — その境目を特定するのは、
ドキュメントの言葉をそのまま信じることではなく、この 1 組のペアです。
最後の列の拒否メッセージはサービス自身の文で、そのまま取得したもので
あり、書き写して手を加えたものではありません。
4 行は拒否側からしか確定できませんでした。これらは CreateTable の制限で、
その受理側を確かめるにはインデックスを 20 個持つテーブルを作り、それぞれが
アクティブになるのを待つ必要があります — その数値は拒否メッセージが
はっきりと述べています。確定方法の列がどれがどちらかを示しています。
これは飾りではありません。
検証済みの制限
| 制限 | 値 | 確定方法 | 超えたときにサービスが返す内容 |
|---|---|---|---|
| アイテムサイズの最大値 | 409,600 バイト | 409,600 は受理、409,601 は拒否 | ValidationException: Item size has exceeded the maximum allowed size |
| パーティションキー値の最大値 | 2,048 バイト | 2,048 は受理、2,049 は拒否 | ValidationException: One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes |
| ソートキー値の最大値 | 1,024 バイト | 1,024 は受理、1,025 は拒否 | ValidationException: One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of 1024 bytes |
| 最大ネスト深度 | 32 レベル | 32 は受理、33 は拒否 | ValidationException: 1 validation error detected: Nesting Levels have exceeded supported limits: Attributes in the item have nested levels beyond supported limit |
| 式の最大長 | 4,096 バイト | 4,096 は受理、4,097 は拒否 | ValidationException: 1 validation error detected: Invalid ConditionExpression: Expression size has exceeded the maximum allowed size; |
| BatchWriteItem あたりの最大アイテム数 | 25 アイテム | 25 は受理、26 は拒否 | ValidationException: 1 validation error detected: Value '<your request>' at 'requestItems' failed to satisfy constraint: Map value must satisfy constraint: [Member must have length less than or equal to 25, Member must have length greater than or equal to 1] |
| BatchGetItem あたりの最大キー数 | 100 アイテム | 100 は受理、101 は拒否 | ValidationException: 1 validation error detected: Value at 'RequestItems.<table-name>.member.Keys' failed to satisfy constraint: Member must have length less than or equal to 100 |
| TransactWriteItems あたりの最大アクション数 | 100 アイテム | 100 は受理、101 は拒否 | ValidationException: 1 validation error detected: Value '<your request>' at 'transactItems' failed to satisfy constraint: Member must have length less than or equal to 100 |
| テーブルあたりのグローバルセカンダリインデックス数 | 20 | 拒否のみ | ValidationException: One or more parameter values were invalid: GlobalSecondaryIndex count exceeds the per-table limit of 20 |
| テーブルあたりのローカルセカンダリインデックス数 | 5 | 拒否のみ | ValidationException: One or more parameter values were invalid: Number of LocalSecondaryIndexes exceeds per-table limit of 5 |
| インデックスあたりの射影された非キー属性数 | 20 | 拒否のみ | ValidationException: 1 validation error detected: Value '<your request>' at 'globalSecondaryIndexes.1.member.projection.nonKeyAttributes' failed to satisfy constraint: Member must have length less than or equal to 20 |
| テーブルあたりの射影された非キー属性数 | 100 | 拒否のみ | ValidationException: One or more parameter values were invalid: Number of projected attributes in all indexes exceeds limit of 100, number of projected attributes:120 |
環境: Amazon DynamoDB、実サービス、us-east-1、2026-08-27 に AWS SDK for
JavaScript v3 で計測。
プローブが明らかにしたこと
「400 KB」は 409,600 バイトを意味し、属性名もカウントに含まれます。 ちょうど 409,600 バイトのアイテムは受理され、409,601 バイトは拒否されました。この 測定はすべての属性名と値の UTF-8 長を合算しており、これは当方の アイテムサイズ計算ツールが実装している のと同じ計算方法です — プローブはそのライブラリを使ってペイロードを組み立てて いるため、両者は主張ではなく構造によって一致しています。この制限の背後にある より深いモデリングの問題には、専用のガイドがあります: DynamoDB のアイテムサイズ上限。
誰もが引用する「射影される属性の上限」は、実は間違ったものです。 AWS の
クォータページ
には「テーブルのローカルおよびグローバルセカンダリインデックスすべてを合わせて
最大 100 属性」という 1 つの数値だけが記載されており、インデックスあたりの
上限には一切触れていません。実際には上限があり、それは 20 です。1 つの
インデックスに 21 個の非キー属性を射影する CreateTable は、テーブル全体の
合計が 100 に近づくよりずっと前に拒否されます。20 という数値もドキュメント化
されてはいますが、それは API リファレンスの
Projection
ページに、配列メンバーの制約として「Maximum number of 20 items」とあるのみ
です。クォータページだけを見てインデックスを設計すると、クォータページが
問題ないとしているスキーマを API が拒否することになります。両方の数値とも、
それを裏づける拒否メッセージとともに上の表にあります。
メッセージのうち 2 つには AWS 自身のタイプミスが含まれています。 ここでは
黙って修正せず、そのまま再掲しています — maximum size limit of2048 bytes
はスペースが 1 つ抜けており、number of projected attributes:120 にも
もう 1 つ抜けています。これらの文字列でログを grep するなら、正しく読める
文字列ではなく、サービスが実際に送ってくる文字列で grep してください。
ソートキーは合算で測定されます。 ソートキーの拒否メッセージが「the sort key」ではなく「Aggregated size of all range keys」と言っているのは、同じ 1,024 バイトの予算が、テーブルのソートキーと、そのアイテムが属するすべての ローカルセカンダリインデックスのソートキーをまとめてカバーしているからです。
何も発生させない 1 MB のページ
上のすべての制限は、拒否によって自らの存在を知らせます。Query と Scan の
ページ制限はそうしません。それを超えると、DynamoDB はエラーも警告もなく、
短いページと LastEvaluatedKey を返すだけです — これが「Scan がテーブルの
一部しか返してこない」という驚きがよくある理由であり、
ページネーションが省略できない理由でもあります。
つまり引用できるエラーメッセージが存在しないため、誘発するのではなく測定 しました:
アイテム 1 件あたり 1,000 バイトのとき、1 ページには1,029 件のアイテム
が収まり LastEvaluatedKey が返されました — アイテムデータ 1,029,000
バイトで、1,030 件目のアイテムは次のリクエストに残されました。アイテム
1 件あたり 5,000 バイトのとき、1 ページには208 件のアイテムが収まり
LastEvaluatedKey が返されました — アイテムデータ 1,040,000 バイトで、
209 件目のアイテムは次のリクエストに残されました。
どちらのページもアイテムデータで 1 MiB を満たしてはいません — 1 つ目は 約 19,576 バイト不足していました。つまりページの予算は、アイテム自体の バイト数より多くを 1 アイテムごとに課しています。
異なる 2 つのアイテムサイズでの計測があれば、これを特定するのに十分です。
ページを アイテム数 × (アイテムのバイト数 + アイテムごとのオーバーヘッド) ≤ 予算 として扱うと、両方の計測値と整合する整数バイトのオーバーヘッドは
7 通りだけであり、そのうちちょうど 1 つだけが予算をきりのよいバイナリの
メガバイトに乗せます — 1 アイテムあたり 19 バイトのオーバーヘッドで、
予算は 1,048,551 バイトから 1,048,971 バイトの間、つまり 1,048,576 を
含む範囲です。DynamoDB の「1 MB」は、自身のクォータページが述べている
とおりバイナリであり、アイテムのバイト数に加えてアイテムごとのオーバー
ヘッドにも使われます。1 アイテムあたりおよそ 19 バイトを見込んでおいて
ください。
実測しなかったクォータ
以下の制限は AWS からの引用であり、実測ではありません。 これらは アカウントレベルのクォータで、多くはリクエストにより引き上げ可能であり、 到達するには時間課金のスループットをプロビジョンする、何千ものテーブルを 作成する、あるいは 1 年分のリザーブドキャパシティにコミットする必要が あります。そのどれもプローブではないため、プローブとしては提示していません。 各行の出典はすべて AWS の Amazon DynamoDB のクォータ ページです。
| クォータ | デフォルト値 | 引き上げ可否 | 実測しなかった理由 |
|---|---|---|---|
| アカウント・リージョンあたりのテーブル数 | 2,500 | 可 | 2,501 個目の失敗を見るために 2,500 個のテーブルを作ると、誰かが片付ける羽目になるアカウントが残ります。 |
| テーブルあたりのプロビジョンドスループット | 40,000 RCU および 40,000 WCU | 可 | 40,000 ユニットをプロビジョンすると、1 件もリクエストを送らなくても時間単位で課金されます。 |
| アカウントあたりのプロビジョンドスループット | 80,000 RCU および 80,000 WCU | 可 | 同じ理由が 2 倍になるうえ、アカウント全体の設定を変えてしまいます。 |
| テーブルあたりのオンデマンドスループット | 40,000 RRU および 40,000 WRU | 可 | 到達するには秒間 40,000 リクエストを維持する必要があり、それは課金付きの負荷テストです。 |
| アカウントあたりのアクティブなリザーブドキャパシティ | 1,000,000 キャパシティユニット | 可 | リザーブドキャパシティは 1 年間の購入コミットメントであり、プローブではありません。 |
| テーブルサイズ | 実用上の制限なし | — | AWS は、テーブルのアイテム数とバイト数には制約がないとしています — 見つけるべき境目がありません。 |
どの制限を前提に設計すべきか
これらのほとんどには一生出会いません。実際の設計を左右する一握りは次の とおりです:
- アイテムあたり 400 KB はクォータではなくモデリング上の制約です。これに 近づくアイテムは、たいてい埋め込みリストとして保存された無制限の 1 対多 リレーションシップです。 アイテムサイズ上限を参照してください。
- 1 MB のページは、あなたが書くすべての Query と Scan を支配します。
LastEvaluatedKeyを無視するコードは、データが 1 ページに収まらなく なった日に、静かに間違ったものになります。 - バッチ書き込みあたり 25 アイテム、バッチ取得あたり 100 アイテムは、 一括ロードのループの形を決めます。 バッチ操作を参照してください。
- トランザクションあたり 100 アクションは、DynamoDB をリレーショナルに 振る舞わせようとした人がぶつかる制限です。 トランザクションを参照してください。
- GSI 20 個、LSI 5 個、射影属性 100 個は、スループットのクォータより はるかに頻繁にアクセスパターンの設計を制約します。しかも LSI の数は テーブル作成の瞬間に固定されます。 インデックスの射影と GSI と LSIを参照してください。
上で引用した拒否メッセージのほとんどは、それぞれを引き起こすリクエストと
ともに、DynamoDB のエラー配下にも専用のページを
持っています。4 つの CreateTable の拒否だけは持っていません — このページの
ために取得したものだからです。
書き込まずに 1 件のアイテムを 400 KB のラインと照らし合わせたいなら、 アイテムサイズ計算ツールがブラウザ上で 動きます。自分のテーブルの中身を見たいなら、DynoTable は デスクトップ向けの DynamoDB クライアントです。