Query do DynamoDB em Python (boto3)

O paginador query do boto3 é a razão de esta página ser curta: ele esconde o LastEvaluatedKey por completo. Ele também esconde um número que você provavelmente queria, e é essa a parte que vale conhecer antes de confiar nele. Para saber quando recorrer ao query, veja Query vs. Scan.

Código

import boto3

client = boto3.client("dynamodb")

paginator = client.get_paginator("query")

items = []
for page in paginator.paginate(
    TableName="Music",
    KeyConditionExpression="#hashKey = :hashKeyValue AND begins_with(#rangeKey, :rangeKeyValue)",
    ExpressionAttributeNames={"#hashKey": "Artist", "#rangeKey": "SongTitle"},
    ExpressionAttributeValues={":hashKeyValue": {"S": "Arturo Sandoval"}, ":rangeKeyValue": {"S": "C"}},
):
    items.extend(page["Items"])

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

O paginador não soma a sua conta

Contra um fixture de 600 músicas, cada uma com ~3,9 KB e todas sob Artist = "Arturo Sandoval", o laço produz três páginas: 271, 271 e 58 itens, custando 128,5, 128,5 e 27,5 unidades de leitura. Peça ao mesmo paginador um resultado único e mesclado e você recebe isto:

build_full_result() -> Items 600  Count 600  ScannedCount 600
                       ConsumedCapacity.CapacityUnits 128.5

Count e ScannedCount foram somados. ConsumedCapacity não — ele é o número da primeira página, e o total real era 284,5. A configuração do paginador de DynamoDB do botocore é explícita sobre o porquê: Count e ScannedCount estão listados como result keys, e ConsumedCapacity como uma non-aggregate key. Se você está registrando capacidade a partir do build_full_result(), está subnotificando a leitura de uma partição inteira em mais da metade.

Os dicts por página no laço for page in paginator.paginate(...) acima são respostas cruas, então somar page["ConsumedCapacity"]["CapacityUnits"] por conta própria te dá os honestos 284,5.

O Limit que te custa 58 idas e voltas extras

Limit é um parâmetro válido de query, então o paginate() o aceita, e ele não é o parâmetro que os usuários de Python esperam:

paginate(..., Limit=10)  ->  61 pages, 10 items each
paginate(...)            ->   3 pages

Ele limita itens por requisição, não no total, então o paginador obedientemente faz 61 chamadas HTTP para buscar os mesmos 600 itens. Para limitar o total, use PaginationConfig={"MaxItems": 10}; o PaginationConfig["PageSize"] é o botão que mapeia para o Limit.

Medido em 2026-07-28 contra o DynamoDB Local (amazon/dynamodb-local) com boto3 1.43.58 no CPython 3.14.6.

Explicação

  • O cliente fala DynamoDB JSON nas duas direções. Os valores entram como {"S": "Arturo Sandoval"} e Year volta como {"N": "1994"}. A API de resource (boto3.resource("dynamodb").Table(...).query) converte nos dois sentidos e te entrega Decimal('1994') — o que é correto para dinheiro e surpreendente na primeira vez que ele se recusa a somar com um float.
  • Key("Artist").eq(...) pertence somente à API de resource. Passá-lo ao cliente gera erro antes de a requisição sair: ParamValidationError: Invalid type for parameter KeyConditionExpression ... valid types: <class 'str'>. O cliente quer a string de expressão que esta página monta.
  • A condição de chave é uma igualdade mais no máximo uma comparação de chave de classificação (=, <, <=, >, >=, BETWEEN, begins_with). Coloque qualquer outra coisa em uma FilterExpression, que o boto3 repassa direto e o DynamoDB aplica depois da leitura. ScanIndexForward=False inverte a ordem e IndexName="..." redireciona para um índice.

Faça isso visualmente

O DynamoDB Expression Builder escreve a condição de chave e o mapa tipado de ExpressionAttributeValues como Python pronto para o boto3, que é justamente a parte que dá errado quando você digita {"N": 2010} em vez de {"N": "2010"}.

Para apontar a mesma consulta às suas próprias tabelas a partir de um formulário de condição de chave e ler os resultados em uma grade paginada, baixe o DynoTable.

Guias relacionados

Referências

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.