Scan do DynamoDB em Python (boto3)

Um scan no boto3 são duas decisões: a requisição, e como você a pagina. O trecho abaixo usa o paginador embutido, que não é um wrapper que alguém escreveu em volta do seu loop. São cinco linhas de configuração do botocore, e essas cinco linhas decidem se o seu scan está correto e quanto ele custa. (Se você deveria estar fazendo scan, para começo de conversa, é outra questão.)

Código

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")

Explicação

  • O paginador é dado, não código. O botocore traz uma entrada por operação em paginators-1.json; a do Scan diz {"input_token": "ExclusiveStartKey", "output_token": "LastEvaluatedKey", "limit_key": "Limit", "result_key": ["Items", "Count", "ScannedCount"], "non_aggregate_keys": ["ConsumedCapacity"]}. Tudo o que vem abaixo decorre dessas chaves.
  • PaginationConfig={"PageSize": n} define o Limit, porque Limit é o limit_key. O Limit limita itens lidos, nunca itens retornados, então com uma FilterExpression uma página pode vir vazia e ainda assim ter custo.
  • MaxItems conta itens de result_key e devolve um NextToken que você pode passar como StartingToken em um processo posterior. Ele não impede a requisição de ler além do seu corte.
  • build_full_result() agrega apenas os campos de result_key. Items, Count e ScannedCount são somados; ConsumedCapacity é uma non_aggregate_key, então o resultado mesclado reporta a capacidade de uma página como se fosse a do scan inteiro. Some você mesmo, por página, ou você vai subnotificar por um fator igual ao número de páginas.
  • A FilterExpression roda no lado do servidor depois da leitura, então você é cobrado por ScannedCount, não por Count. #filter0 dá alias a Year porque é uma palavra reservada; sem o alias a requisição falha antes de ler qualquer coisa.
  • Os erros todos chegam como botocore.exceptions.ClientError. Ramifique por e.response["Error"]["Code"]; as classes por erro existem apenas como atributos gerados no cliente (client.exceptions.ProvisionedThroughputExceededException), nunca como símbolos importáveis.
  • A API de recurso é a outra ergonomia. Table.scan recebe tipos nativos do Python, retorna números como decimal.Decimal e monta filtros com Attr("Year").gte(2010) em vez de mapas de placeholders.

Quanto custa de verdade uma página filtrada

60 itens de aproximadamente 2 KB cada, Year = 2024 casando com dois deles, PageSize=10, executado contra o 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

Quatro das seis páginas reais não retornaram nada, a preço cheio. Esse é o formato do bug que o paginador existe para prevenir: um loop feito à mão que para quando Items está vazio desiste na página 1 e reporta duas músicas correspondentes como zero.

A página 7 é a outra metade. A página 6 bateu no seu Limit no último item da tabela, então o DynamoDB retornou um LastEvaluatedKey mesmo assim e o paginador gastou mais uma ida e volta para descobrir que não sobrou nada. Um LastEvaluatedKey significa "eu parei", não "tem mais".

Chamar build_full_result() no mesmo scan reporta CapacityUnits: 2.5. As seis páginas consumiram 15,0.

Paginar sem escrever o loop

O DynamoDB Query Builder monta o filtro, o mapa de aliases e o loop de paginação como um único programa executável, então a armadilha de Limit versus Count acima já vem resolvida antes de você colar o código. Para paginar uma tabela real de forma interativa em vez de por script, baixe o DynoTable.

Guias relacionados

Referências

Verificado pela última vez em 2026-07-28 contra a documentação oficial da AWS vinculada acima.

Monte esta solicitação visualmente

Componha esta operação no Construtor de Consultas do DynamoDB gratuito — key condition, filtro, índice, Limit, ordem de classificação e um laço de paginação — e copie de volta como um programa executável para SDK v3, CLI ou boto3.

Abrir o Construtor de Consultas do DynamoDB

Trabalhe com o DynamoDB sem o Console

Um cliente desktop rápido para DynamoDB que roda o SQL de verdade que o DynamoDB não consegue — JOINs, GROUP BY, agregações — com edição visual e um agente de IA com suas próprias chaves do Bedrock.

Teste grátis de 30 dias, sem cartão de crédito — depois o plano Grátis sem limite de tempo.