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", [])을 씁니다.
  • ConsistentReadProjectionExpression은 테이블별 딕셔너리 안, "Keys" 옆에 들어가며 RequestItems 옆이 아닙니다. boto3는 잘못 놓인 키도 군말 없이 보내고 서비스가 거부하게 둡니다.
  • 이것은 저수준 클라이언트이므로 값은 DynamoDB JSON입니다({"S": ...}, {"N": ...}). 리소스 API에서는 batch_get_itemTable이 아니라 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:  # AttributeError

botocore는 DynamoDB 클라이언트에 이름이 붙은 예외 클래스 34개를 모델링하는데, ValidationException은 그중에 없습니다. ConditionalCheckFailedExceptionProvisionedThroughputExceededException은 있으며, 그래서 조건부 쓰기 페이지는 클래스로 잡을 수 있고 이 페이지는 그럴 수 없습니다. 심지어 모델링된 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을 다운로드하세요.

관련 예제

참고 자료

위에 링크된 공식 AWS 문서를 기준으로 2026-07-28에 마지막으로 검증했습니다.

Console 없이 DynamoDB 작업하기

DynamoDB로는 실행할 수 없는 진짜 SQL(JOINs, GROUP BY, 집계)을 실행하는 빠른 DynamoDB 데스크톱 클라이언트. 시각적 편집과 여러분 자신의 Bedrock 키로 동작하는 AI 에이전트를 제공합니다.

30일 무료 체험, 신용카드 불필요 — 이후 기간 제한 없는 무료 요금제.