Python(boto3)中的 DynamoDB BatchGetItem
batch_get_item 會在一次請求中,依主索引鍵取回最多 100 個項目。下方程式碼裡的 while request_items: 就是整個 boto3 慣用寫法:DynamoDB 會在一次_成功_的回應裡把剩下沒處理的交還給你,而空字典是 falsy,所以迴圈會自己結束。限制與部分結果的規則放在 DynamoDB 的批次操作;這一頁談的是 boto3 的呼叫本身,以及它會丟出的錯誤。
程式碼
import time
import boto3
client = boto3.client("dynamodb")
request_items = {
"Music": {
"Keys": [
{"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "Cubano Chant"}},
{"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "A Mis Abuelos"}},
{"Artist": {"S": "Ella Fitzgerald"}, "SongTitle": {"S": "Misty"}},
]
}
}
items = []
attempt = 0
while request_items:
response = client.batch_get_item(RequestItems=request_items)
items.extend(response["Responses"].get("Music", []))
# A partial result is NOT an error: throttling, a >16 MB response, or an
# internal failure returns the leftovers in UnprocessedKeys. Retry them
# with exponential backoff.
request_items = response["UnprocessedKeys"]
if request_items:
attempt += 1
time.sleep(min(0.1 * 2**attempt, 5))
print(f"Fetched {len(items)} items")說明
response["UnprocessedKeys"]永遠都在。在完全服務完的批次上,這個鍵仍然存在、值為{},所以request_items = response["UnprocessedKeys"]可以安全地取用,而那個 falsy 的空字典正是結束while的東西。真正要小心的是Responses:如果某張資料表的索引鍵全都沒命中,它就不會出現在裡面,這也是程式碼裡用.get("Music", [])的原因。ConsistentRead與ProjectionExpression要放在每張資料表各自的字典裡,跟"Keys"並排,而不是跟RequestItems並排。boto3 會很樂意把放錯位置的鍵送出去,然後讓服務去回絕它。- 這是低階 client,所以值是 DynamoDB JSON(
{"S": ...}、{"N": ...})。resource API 的batch_get_item掛在 ServiceResource 上,而不是Table上。boto3.resource("dynamodb").batch_get_item(...)收的是原生 Python 值;table.batch_get_item根本不存在。這種不對稱會讓用過table.batch_writer()之後順手去找它的人吃一驚,因為後者_確實_是Table的方法。 - 退避只適用於
UnprocessedKeys。ValidationException是請求本身的臭蟲,重試它只是在燒時鐘。
這次呼叫會丟出的兩個錯誤,逐字原文
兩者都是用戶端的錯誤,重試都救不了,而且都以單純的 botocore.exceptions.ClientError 浮現。在 DynamoDB Local 3.3.0 上,str(e) 是:
An error occurred (ValidationException) when calling the BatchGetItem operation: Too many items requested for the BatchGetItem call
An error occurred (ValidationException) when calling the BatchGetItem operation: Provided list of item keys contains duplicates第一個是 101 個索引鍵,第二個是同一個索引鍵列了兩次。請注意你不能這樣寫來攔截它們:
except client.exceptions.ValidationException: # AttributeErrorbotocore 在 DynamoDB client 上模型化了 34 個具名例外類別,而 ValidationException 不在其中。ConditionalCheckFailedException 與 ProvisionedThroughputExceededException 都在,這也是為什麼條件式寫入那一頁可以依類別攔截,而這一頁不行。甚至還有一個模型化的 DuplicateItemException,而它不是批次裡出現重複索引鍵時你會拿到的東西。所以批次讀取只能依錯誤代碼分支:
except ClientError as e:
if e.response["Error"]["Code"] == "ValidationException":
raise # a bug in the request; retrying will not help重複索引鍵才是真實程式碼裡會咬人的那一個,因為從 Query 結果或關聯表組出來的索引鍵清單,本來就很自然會重複。送出前先去重,並記得:兩個字典要每一個索引鍵屬性都相同才算相等。
大小是 100 個項目的批次留不住 100 個的另一個原因:每個項目在計費時會無條件進位到 4 KB,並計入回應的 16 MB 上限,所以 100 個 300 KB 的項目大約只會回來 52 個,其餘落在 UnprocessedKeys 裡。項目大小計算機會給你可以拿來相乘的每項目數字。
想在寫那個迴圈之前先把一組索引鍵拉回來、看看到底回了什麼,請下載 DynoTable。
相關範例
- Node.js 中的 DynamoDB BatchGetItem — 用 AWS SDK v3 做同一種批次讀取。
- 用 AWS CLI 執行 DynamoDB BatchGetItem — 從 shell 做同一種批次讀取。
- Python 中的 DynamoDB GetItem — 被它批次化的單一項目讀取。
- DynamoDB 的批次操作 — 限制、部分失敗,以及批次划算的時機。
- 「Too many items requested for the BatchGetItem call」 — 一次請求裡超過 100 個索引鍵。
- 「Provided list of item keys contains duplicates」 — 同一批次裡出現兩次同一個索引鍵。
參考資料
- BatchGetItem — Amazon DynamoDB API Reference
- DynamoDB.Client.batch_get_item — Boto3 documentation
- Error handling with DynamoDB — Amazon DynamoDB Developer Guide
最後驗證於 2026-07-28,對照上方連結的 AWS 官方文件。