Scan DynamoDB in Python (boto3)

Uno scan in boto3 sono due decisioni: la richiesta, e come la pagini. Lo snippet qui sotto usa il paginator integrato, che non è un wrapper che qualcuno ha scritto attorno al tuo loop. Sono cinque righe di configurazione botocore, e quelle cinque righe decidono se il tuo scan è corretto e quanto costa. (Se dovresti proprio fare uno scan è un'altra questione.)

Codice

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

Spiegazione

  • Il paginator è dato, non codice. botocore fornisce una voce per operazione in paginators-1.json; quella di Scan recita {"input_token": "ExclusiveStartKey", "output_token": "LastEvaluatedKey", "limit_key": "Limit", "result_key": ["Items", "Count", "ScannedCount"], "non_aggregate_keys": ["ConsumedCapacity"]}. Tutto quello che segue discende da quelle chiavi.
  • PaginationConfig={"PageSize": n} imposta Limit, perché Limit è il limit_key. Limit limita gli Item letti, mai gli Item restituiti, quindi con una FilterExpression una pagina può essere vuota e avere comunque un costo.
  • MaxItems conta gli Item di result_key e restituisce un NextToken che puoi passare come StartingToken in un processo successivo. Non impedisce alla richiesta di leggere oltre il tuo limite.
  • build_full_result() aggrega solo i campi di result_key. Items, Count e ScannedCount vengono sommati; ConsumedCapacity è una non_aggregate_key, quindi il risultato unito riporta la capacità di una sola pagina come se fosse quella dell'intero scan. Sommala tu, pagina per pagina, altrimenti sottostimerai di un fattore pari al numero di pagine.
  • FilterExpression viene eseguita lato server dopo la lettura, quindi ti viene fatturato ScannedCount, non Count. #filter0 aliasa Year perché è una parola riservata; senza l'alias la richiesta fallisce prima di leggere qualsiasi cosa.
  • Gli errori arrivano tutti come botocore.exceptions.ClientError. Ramifica su e.response["Error"]["Code"]; le classi per singolo errore esistono solo come attributi generati sul client (client.exceptions.ProvisionedThroughputExceededException), mai come simboli importabili.
  • L'API resource è l'altra ergonomia. Table.scan prende tipi Python nativi, restituisce i numeri come decimal.Decimal e costruisce i filtri con Attr("Year").gte(2010) invece che con mappe di placeholder.

Quanto costa davvero una pagina filtrata

60 Item di circa 2 KB ciascuno, con Year = 2024 che ne corrisponde due, PageSize=10, eseguito su 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

Quattro delle sei pagine reali non hanno restituito nulla, a prezzo pieno. È la forma del bug che il paginator esiste per prevenire: un loop fatto in casa che si interrompe quando Items è vuoto esce alla pagina 1 e riporta zero invece dei due brani corrispondenti.

La pagina 7 è l'altra metà. La pagina 6 ha raggiunto il suo Limit sull'ultimo Item della tabella, quindi DynamoDB ha comunque restituito un LastEvaluatedKey e il paginator ha speso un altro round trip per scoprire che non era rimasto nulla. Un LastEvaluatedKey significa "mi sono fermato", non "c'è dell'altro".

Chiamare build_full_result() sullo stesso scan riporta CapacityUnits: 2.5. Le sei pagine ne hanno consumate 15,0.

Paginare senza scrivere il loop

Il DynamoDB Query Builder assembla il filtro, la mappa di alias e il loop di paginazione come un unico programma eseguibile, così la trappola Limit-contro-Count qui sopra è già gestita prima che tu lo incolli. Per paginare una tabella reale in modo interattivo invece che da uno script, scarica DynoTable.

Guide correlate

Riferimenti

Ultima verifica 2026-07-28 rispetto alla documentazione ufficiale AWS collegata sopra.

Costruisci questa richiesta visivamente

Componi questa operazione nel Generatore di query DynamoDB gratuito — condizione di chiave, filtro, indice, Limit, ordine di ordinamento e un loop di paginazione — e copiala come programma eseguibile per SDK v3, CLI o boto3.

Apri il Generatore di query DynamoDB

Lavora con DynamoDB senza la Console

Un client desktop veloce per DynamoDB che esegue il vero SQL che DynamoDB non può — JOINs, GROUP BY, aggregazioni — con modifica visuale e un agente AI sulle tue chiavi Bedrock.

Prova gratuita di 30 giorni, senza carta di credito — poi il piano Free senza limiti di tempo.