DynamoDB 限制與配額,經即時服務驗證
DynamoDB 有哪些限制?
一個項目上限是 400 KB,partition key 上限是 2,048 位元組,sort key 上限是 1,024 位元組。一次批次寫入最多 25 個項目,一次批次讀取最多 100 個鍵,一次事務最多 100 個動作。 一張表最多有 20 個全域次要索引與 5 個本地次要索引。本頁的每一個數字,都是透過把請求真的 送到 Amazon DynamoDB、再讀取它回傳了什麼來確立的。
這些數字是怎麼確立的
AWS 公佈它的配額時並不附證據,這通常沒什麼問題——直到某個數字成了一項設計決策的 承重牆,而你想知道它指的究竟是 400,000 位元組還是 409,600,它算不算你的屬性名,以及 超出時服務究竟會說什麼。
所以我們去實測了它們。對下面第一張表裡的每一項限制,我們構造一個請求,讓它恰好落在
文件記載的那個值上,送到 us-east-1 的即時服務;接著再送第二個請求,比那個值多一個
單位。第一個必須被接受,第二個必須被拒絕——正是這一對請求定出了那條邊界,而不是照抄
文件的說法。最後一欄的拒絕訊息是服務自己的原句,原樣擷取,從未重打。
有四列只能從拒絕那一側確立。那些是 CreateTable 的限制,若要從接受那一側確立,就得
真的建一張帶二十個索引的表、並等每一個都變成 active,而拒絕方那個數字已經直接說出來了。
如何驗證得出那一欄寫明了是哪一種;那不是裝飾用的。
經驗證的限制
| 限制項 | 值 | 如何驗證得出 | 超出時服務回傳的內容 |
|---|---|---|---|
| 項目最大大小 | 409,600 位元組 | 409,600 被接受,409,601 被拒絕 | ValidationException: Item size has exceeded the maximum allowed size |
| partition key 值上限 | 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 |
| sort key 值上限 | 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 個屬性」——完全沒有提到
每個索引各自的上限。其實是有的,而且是 20。一個把 21 個非鍵屬性投影進單一索引的
CreateTable 請求會被拒絕,遠遠不到每表 100 的總量。這個 20 是有記載的,但只出現在
API 參考文件的
Projection
頁面裡,作為一項陣列成員限制:「Maximum number of 20 items」。如果你只照著配額頁面規劃
一個索引,API 會拒絕一個配額頁面說沒問題的 schema。這兩個數字都在上表裡,各自附有能
證明它的拒絕原文。
其中兩則訊息裡帶著 AWS 自己的錯字,這裡原樣重現而不是悄悄改正——
maximum size limit of2048 bytes 少了一個空格,number of projected attributes:120
也少了一個空格。如果你在用這些字串搜尋日誌,請照服務實際傳送的內容去搜,而不是照讀起來
順眼的版本去搜。
sort key 是按彙總值計量的。 sort key 的拒絕訊息說的是「Aggregated size of all range keys」,而不是「the sort key」,因為同一個 1,024 位元組的預算涵蓋了這張表的 sort key,以及該項目落入的每一個本地次要索引的 sort key。
1 MB 分頁,它什麼都不會拋出
上面的每一項限制都會用拒絕請求來宣告自己的存在。Query 和 Scan 的分頁限制不會。跨過它,
DynamoDB 只會回傳一個較短的分頁與一個 LastEvaluatedKey,沒有錯誤也沒有警告——這就是
「我的 Scan 只回傳了表的一部分」會是個常見驚喜的原因,也是為什麼
分頁不是可選項的原因。
這也意味著沒有錯誤訊息可以引用,所以它是被測量出來的,而不是被激發出來的:
在每個項目 1,000 位元組時,一個分頁裝了 1,029 個項目並回傳了一個
LastEvaluatedKey——1,029,000 位元組的項目資料,第 1,030 個項目被留給下一個請求。在
每個項目 5,000 位元組時,一個分頁裝了 208 個項目並回傳了一個
LastEvaluatedKey——1,040,000 位元組的項目資料,第 209 個項目被留給下一個請求。
兩個分頁都沒有裝滿 1 MiB 的項目資料——第一個少了大約 19,576 位元組。所以分頁預算對每個 項目收取的,比項目本身的位元組數還要多。
在兩種不同項目大小下各測一次,就足以把這件事定下來。把一個分頁視為
項目數 × (項目位元組 + 每項目額外開銷) ≤ 預算,只有 7 個整數位元組的額外開銷同時
符合這兩次測量,而其中恰好有一個把預算落在一個整數二進位百萬位元組上:每個項目
19 位元組的額外開銷,預算落在 1,048,551 到 1,048,971 位元組之間——這個範圍包含
1,048,576。DynamoDB 的「1 MB」是二進位的,正如它自己的配額頁面所述,而它花在項目
位元組加上每項目額外開銷上。為每個項目大約預留 19 位元組的額外開銷。
我們沒有實測的配額
下面這些限制是引自 AWS,而不是實測出來的。 它們是帳戶層級的配額:大多數可以申請 調整,而要碰到它們,就意味著要佈建按小時計費的輸送量、建立成千上萬張表,或者承諾一整年 的預留容量。這些都不是探測,所以也不會被當成探測呈現。每一列的來源都是 AWS 的 Amazon DynamoDB 配額 頁面。
| 配額 | 預設值 | 可調整 | 我們為什麼沒有實測它 |
|---|---|---|---|
| 每個帳戶、每個區域的表數量 | 2,500 | 是 | 為了看第 2,501 張表失敗而建 2,500 張表,會留下一堆得有人善後的表。 |
| 每張表的佈建輸送量 | 40,000 RCU 與 40,000 WCU | 是 | 佈建 40,000 個單位,無論有沒有發出任何請求都按小時計費。 |
| 每個帳戶的佈建輸送量 | 80,000 RCU 與 80,000 WCU | 是 | 同樣的理由再乘以二——而且它改動的是整個帳戶層級的設定。 |
| 每張表的隨需輸送量 | 40,000 RRU 與 40,000 WRU | 是 | 要碰到它,意味著要撐住每秒 40,000 個請求,那是一場帶帳單的負載測試。 |
| 每個帳戶的作用中預留容量 | 1,000,000 容量單位 | 是 | 預留容量是一年期的購買承諾,不是一次探測。 |
| 表大小 | 沒有實際上限 | — | AWS 表示表在項目數與位元組數上都不受限;沒有邊界可找。 |
你應該圍繞哪些限制去做設計
這裡面大多數你永遠不會碰到。真正塑造實際設計的是這幾個:
- 每個項目 400 KB 是一項建模約束,而不是一項配額。一個逼近它的項目,通常是被存成 內嵌 List 的一段無界一對多關係。參見 項目大小限制。
- 1 MB 分頁支配著你寫的每一個 Query 和 Scan。忽略
LastEvaluatedKey的程式碼,在 你的資料超出一個分頁的那一天,就會悄悄出錯。 - 每次批次寫入 25 個項目、每次批次讀取 100 個塑造著你的批次載入迴圈。參見 批次操作。
- 每次事務 100 個動作是大家在試圖讓 DynamoDB 表現得像關聯式資料庫時最容易撞上的那個。 參見事務。
- 20 個 GSI、5 個 LSI、100 個投影屬性對存取模式設計的約束,遠比輸送量配額更常見, 而且 LSI 數量在建表那一刻就固定下來了。參見 索引投影與 GSI 對 LSI。
上面引用的大多數拒絕,在 DynamoDB 錯誤之下也有它們自己的一頁,附上
產生每一則訊息的請求。那四個 CreateTable 的拒絕沒有——它們是專為本頁擷取的。
要在不真的寫入的情況下,對照 400 KB 這條線檢查單一個項目, 項目大小計算器可以在你的瀏覽器裡執行。 要檢視你自己表裡的項目,DynoTable 是一款桌面版的 DynamoDB 用戶端。