Python(boto3)의 DynamoDB Scan

boto3에서 scan은 두 가지 결정입니다. 요청, 그리고 그것을 어떻게 페이지네이션하느냐. 아래 스니펫은 내장 페이지네이터를 씁니다. 누군가 여러분의 루프를 감싸 만든 래퍼가 아닙니다. botocore 설정 다섯 줄이며, 그 다섯 줄이 여러분의 Scan이 올바른지와 비용이 얼마인지를 결정합니다. (애초에 Scan을 해야 하는지는 다른 질문입니다.)

코드

import boto3

client = boto3.client("dynamodb")

paginator = client.get_paginator("scan")

items = []
for page in paginator.paginate(
    TableName="Music",
    FilterExpression="#filter0 >= :filterValue0",
    ExpressionAttributeNames={"#filter0": "Year"},
    ExpressionAttributeValues={":filterValue0": {"N": "2010"}},
):
    items.extend(page["Items"])

print(f"Matched {len(items)} items")

설명

  • 페이지네이터는 코드가 아니라 데이터입니다. botocore는 paginators-1.json에 작업당 항목 하나를 담아 배포하며, Scan의 항목은 {"input_token": "ExclusiveStartKey", "output_token": "LastEvaluatedKey", "limit_key": "Limit", "result_key": ["Items", "Count", "ScannedCount"], "non_aggregate_keys": ["ConsumedCapacity"]}입니다. 아래의 모든 것이 이 키들에서 따라 나옵니다.
  • PaginationConfig={"PageSize": n}Limit을 설정합니다. Limitlimit_key이기 때문입니다. Limit읽는 항목 수를 제한할 뿐 반환되는 항목 수는 제한하지 않으므로, FilterExpression이 있으면 페이지가 비어 있으면서도 비용은 들 수 있습니다.
  • MaxItemsresult_key 항목을 셉니다. 그리고 나중 프로세스에서 StartingToken으로 전달할 수 있는 NextToken을 돌려줍니다. 요청이 여러분의 컷오프를 넘겨 읽는 것을 막지는 않습니다.
  • build_full_result()result_key 필드만 집계합니다. Items, Count, ScannedCount는 합산되지만 ConsumedCapacitynon_aggregate_key이므로, 병합된 결과는 한 페이지의 용량을 마치 Scan 전체의 것인 양 보고합니다. 페이지마다 직접 합산하세요. 그러지 않으면 페이지 수만큼 과소 보고하게 됩니다.
  • FilterExpression은 읽기 후 서버 측에서 실행되므로, 요금은 Count가 아니라 ScannedCount 기준입니다. Year예약어이므로 #filter0으로 별칭을 붙였습니다. 별칭이 없으면 요청은 아무것도 읽기 전에 실패합니다.
  • 오류는 모두 botocore.exceptions.ClientError로 도착합니다. e.response["Error"]["Code"]로 분기하세요. 오류별 클래스는 클라이언트에 생성되는 속성(client.exceptions.ProvisionedThroughputExceededException)으로만 존재하며, 임포트할 수 있는 심볼로는 존재하지 않습니다.
  • 리소스 API는 또 다른 사용성입니다. Table.scan은 네이티브 Python 타입을 받고, 숫자를 decimal.Decimal로 반환하며, 플레이스홀더 맵 대신 Attr("Year").gte(2010)으로 필터를 만듭니다.

필터가 걸린 페이지 하나의 실제 비용

각각 약 2 KB인 항목 60개, 그중 둘이 Year = 2024에 해당하고, PageSize=10으로 DynamoDB Local을 상대로 실행했습니다:

page 1: Count=0 ScannedCount=10 CU=2.5 LastEvaluatedKey=yes
page 2: Count=1 ScannedCount=10 CU=2.5 LastEvaluatedKey=yes
page 3: Count=0 ScannedCount=10 CU=2.5 LastEvaluatedKey=yes
page 4: Count=1 ScannedCount=10 CU=2.5 LastEvaluatedKey=yes
page 5: Count=0 ScannedCount=10 CU=2.5 LastEvaluatedKey=yes
page 6: Count=0 ScannedCount=10 CU=2.5 LastEvaluatedKey=yes
page 7: Count=0 ScannedCount=0 CU=0.0 LastEvaluatedKey=no
total CU across pages: 15.0

실제 페이지 여섯 개 중 넷이 아무것도 반환하지 않았고, 값은 그대로 치렀습니다. 이것이 페이지네이터가 막으려고 존재하는 버그의 모습입니다. Items가 비면 끊는 직접 만든 루프는 1페이지에서 그만두고, 조건에 맞는 두 곡을 0곡으로 보고합니다.

7페이지가 나머지 절반입니다. 6페이지가 테이블의 마지막 항목에서 Limit에 걸렸기 때문에 DynamoDB는 그래도 LastEvaluatedKey를 반환했고, 페이지네이터는 남은 것이 없다는 사실을 알아내려고 왕복을 한 번 더 썼습니다. LastEvaluatedKey는 "더 있다"가 아니라 "내가 멈췄다"는 뜻입니다.

같은 Scan에서 build_full_result()를 호출하면 CapacityUnits: 2.5를 보고합니다. 여섯 페이지가 소비한 것은 15.0입니다.

루프를 쓰지 않고 페이지 넘기기

DynamoDB 쿼리 빌더는 필터, 별칭 맵, 페이지네이션 루프를 하나의 실행 가능한 프로그램으로 조립하므로, 위의 LimitCount 함정이 붙여 넣기 전에 처리되어 있습니다. 스크립트가 아니라 대화형으로 실제 테이블을 페이지네이션하려면, DynoTable을 다운로드하세요.

관련 가이드

참고 자료

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

이 요청을 시각적으로 만들기

무료 DynamoDB 쿼리 빌더에서 이 작업을 구성하세요 — 키 조건, 필터, 인덱스, Limit, 정렬 순서, 페이지네이션 루프 — 그리고 실행 가능한 SDK v3, CLI, boto3 프로그램으로 다시 복사하세요.

DynamoDB 쿼리 빌더 열기

Console 없이 DynamoDB 작업하기

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

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