DynamoDB Scan in Python (boto3)
Ein scan in boto3 sind zwei Entscheidungen: der Request und wie du ihn blätterst. Das Snippet unten nutzt den eingebauten Paginator, der kein Wrapper ist, den jemand um deine Schleife geschrieben hat. Es sind fünf Zeilen botocore-Konfiguration, und diese fünf Zeilen entscheiden, ob dein Scan korrekt ist und was er kostet. (Ob du überhaupt scannen solltest, ist eine andere Frage.)
Code
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")Erklärung
- Der Paginator ist Daten, kein Code. botocore liefert einen Eintrag pro Operation in
paginators-1.json; der vonScanliest{"input_token": "ExclusiveStartKey", "output_token": "LastEvaluatedKey", "limit_key": "Limit", "result_key": ["Items", "Count", "ScannedCount"], "non_aggregate_keys": ["ConsumedCapacity"]}. Alles Weitere folgt aus diesen Keys. PaginationConfig={"PageSize": n}setztLimit, weilLimitderlimit_keyist.Limitbegrenzt gelesene Items, nie zurückgegebene — mit einerFilterExpressionkann eine Seite also leer sein und trotzdem kosten.MaxItemszähltresult_key-Items und gibt dir einNextTokenzurück, das du in einem späteren Prozess alsStartingTokenübergeben kannst. Es hindert den Request nicht daran, über deine Grenze hinaus zu lesen.build_full_result()aggregiert nur dieresult_key-Felder.Items,CountundScannedCountwerden summiert;ConsumedCapacityist einnon_aggregate_key, das zusammengeführte Ergebnis meldet also die Kapazität einer Seite, als wäre sie die des ganzen Scans. Summiere sie selbst, pro Seite, sonst untertreibst du um den Faktor der Seitenanzahl.FilterExpressionläuft serverseitig nach dem Lesen, du wirst also aufScannedCountabgerechnet, nicht aufCount.#filter0aliasiertYear, weil es ein reserviertes Wort ist; ohne den Alias scheitert der Request, bevor er irgendetwas liest.- Fehler kommen alle als
botocore.exceptions.ClientErroran. Verzweige übere.response["Error"]["Code"]; die Klassen pro Fehler existieren nur als Attribute, die auf dem Client generiert werden (client.exceptions.ProvisionedThroughputExceededException), nie als importierbare Symbole. - Die Resource-API ist die andere Ergonomie.
Table.scannimmt native Python-Typen, gibt Zahlen alsdecimal.Decimalzurück und baut Filter mitAttr("Year").gte(2010)statt Platzhalter-Maps.
Was eine gefilterte Seite tatsächlich kostet
60 Items von jeweils rund 2 KB, Year = 2024 trifft auf zwei davon zu, PageSize=10, ausgeführt gegen 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.0Vier der sechs echten Seiten gaben nichts zurück, zum vollen Preis. Das ist die Form des Bugs, den es zu verhindern gilt: eine selbstgebaute Schleife, die abbricht, wenn Items leer ist, hört auf Seite 1 auf und meldet zwei passende Songs als null.
Seite 7 ist die andere Hälfte. Seite 6 hat ihr Limit beim letzten Item der Tabelle erreicht, DynamoDB gab trotzdem einen LastEvaluatedKey zurück, und der Paginator hat einen weiteren Roundtrip aufgewendet, um zu erfahren, dass nichts mehr da war. Ein LastEvaluatedKey heißt „ich habe angehalten", nicht „es gibt mehr".
build_full_result() auf denselben Scan angewendet meldet CapacityUnits: 2.5. Die sechs Seiten haben 15,0 verbraucht.
Blättern, ohne die Schleife zu schreiben
Der DynamoDB Query Builder setzt den Filter, die Alias-Map und die Pagination-Schleife zu einem lauffähigen Programm zusammen, sodass die Limit-gegen-Count-Falle oben erledigt ist, bevor du es einfügst. Um eine echte Tabelle interaktiv statt aus einem Skript zu blättern, lade DynoTable herunter.
Verwandte Leitfäden
- Query vs. Scan — wann ein
scan(selten) gerechtfertigt ist. - Warum ist mein DynamoDB-Scan langsam und teuer? — das Kostenmodell und wie du es vermeidest.
- Parallel Scans — die Tabelle mit
Segment/TotalSegmentsaufteilen, ein Paginator pro Segment. - DynamoDB ProvisionedThroughputExceededException — was ein Full-Table-Scan mit der Kapazität einer provisionierten Tabelle macht.
Referenzen
- Scan — Amazon DynamoDB API Reference
- scan — Boto3 DynamoDB.Client Reference
- Scan paginator — Boto3 DynamoDB Reference
- Scanning tables — Amazon DynamoDB Developer Guide
Zuletzt verifiziert am 2026-07-28 gegen die oben verlinkte offizielle AWS-Dokumentation.