Python(boto3)의 DynamoDB BatchGetItem
batch_get_item은 한 번의 요청으로 기본 키 기준 항목을 최대 100개 가져옵니다. 아래 코드 블록의 while request_items:가 boto3 관용구의 전부입니다. DynamoDB는 성공한 응답에서 남은 키를 돌려주고, 빈 딕셔너리는 거짓이므로 루프가 스스로 끝납니다. 한도와 부분 결과 규칙은 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"]는 안전하게 인덱싱할 수 있고 거짓인 빈 딕셔너리가while을 끝냅니다. 조심해야 할 쪽은Responses입니다. 키가 하나도 맞지 않은 테이블은 여기에서 아예 빠지며, 그래서 코드 블록이.get("Music", [])을 씁니다.ConsistentRead와ProjectionExpression은 테이블별 딕셔너리 안,"Keys"옆에 들어가며RequestItems옆이 아닙니다. boto3는 잘못 놓인 키도 군말 없이 보내고 서비스가 거부하게 둡니다.- 이것은 저수준 클라이언트이므로 값은 DynamoDB JSON입니다(
{"S": ...},{"N": ...}). 리소스 API에서는batch_get_item이Table이 아니라 ServiceResource에 있습니다.boto3.resource("dynamodb").batch_get_item(...)은 네이티브 Python 값을 받지만,table.batch_get_item은 존재하지 않습니다. 이 비대칭은table.batch_writer()를 쓰고 나서 손을 뻗은 사람들을 놀라게 합니다.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 클라이언트에 이름이 붙은 예외 클래스 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로 계산되므로, 300 KB짜리 항목 100개는 대략 52개만 돌아오고 나머지는 UnprocessedKeys에 담깁니다. 항목 크기 계산기가 곱할 항목당 수치를 알려 줍니다.
루프를 짜기 전에 키 묶음을 가져와 무엇이 반환되는지 살펴보려면 DynoTable을 다운로드하세요.
관련 예제
- Node.js의 DynamoDB BatchGetItem — AWS SDK v3로 하는 같은 배치 읽기.
- AWS CLI를 사용한 DynamoDB BatchGetItem — 셸에서 하는 같은 배치 읽기.
- 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
위에 링크된 공식 AWS 문서를 기준으로 2026-07-28에 마지막으로 검증했습니다.