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 diScanrecita{"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}impostaLimit, perchéLimitè illimit_key.Limitlimita gli Item letti, mai gli Item restituiti, quindi con unaFilterExpressionuna pagina può essere vuota e avere comunque un costo.MaxItemsconta gli Item diresult_keye restituisce unNextTokenche puoi passare comeStartingTokenin un processo successivo. Non impedisce alla richiesta di leggere oltre il tuo limite.build_full_result()aggrega solo i campi diresult_key.Items,CounteScannedCountvengono sommati;ConsumedCapacityè unanon_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.FilterExpressionviene eseguita lato server dopo la lettura, quindi ti viene fatturatoScannedCount, nonCount.#filter0aliasaYearperché è una parola riservata; senza l'alias la richiesta fallisce prima di leggere qualsiasi cosa.- Gli errori arrivano tutti come
botocore.exceptions.ClientError. Ramifica sue.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.scanprende tipi Python nativi, restituisce i numeri comedecimal.Decimale costruisce i filtri conAttr("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.0Quattro 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
- Query vs. Scan — quando (raramente) uno
scanè giustificato. - Perché il mio Scan DynamoDB è lento e costoso? — il modello di costo e come evitarlo.
- Scan paralleli — dividere la tabella con
Segment/TotalSegments, un paginator per segmento. - DynamoDB ProvisionedThroughputExceededException — cosa fa uno scan sull'intera tabella alla capacità di una tabella con provisioning.
Riferimenti
- Scan — Amazon DynamoDB API Reference
- scan — Boto3 DynamoDB.Client Reference
- Scan paginator — Boto3 DynamoDB Reference
- Scanning tables — Amazon DynamoDB Developer Guide
Ultima verifica 2026-07-28 rispetto alla documentazione ufficiale AWS collegata sopra.