Avanzato7 min di lettura

Scansioni parallele in DynamoDB

Una scansione parallela suddivide uno Scan in N richieste Scan indipendenti, ciascuna che rivendica un Segment della tabella, così che più worker la leggano insieme. È l'unico modo per leggere un'intera tabella più velocemente di quanto consenta il throughput di una singola partizione.

Cos'è una scansione parallela di DynamoDB?

Una scansione parallela di DynamoDB suddivide uno Scan in N richieste indipendenti, ciascuna che rivendica un Segment della tabella tramite Segment e TotalSegments, così che più worker la leggano in modo concorrente. È l'unico modo per leggere un'intera tabella più velocemente di quanto consenta il throughput di una singola partizione — ma è pur sempre una lettura completa, quindi paghi per ogni item scansionato.

  • Uno Scan sequenziale legge una partizione alla volta — la sua velocità è limitata dal throughput di una singola partizione, non importa quanto sia grande la tabella.
  • Segment + TotalSegments suddividono la lettura tra TotalSegments worker; ogni worker scansiona la propria fetta in parallelo.
  • DynamoDB fa l'hash della partition key per assegnare i segmenti, quindi le fette possono essere sbilanciate — più worker non significa sempre più veloce.
  • È pur sempre uno Scan: paghi per leggere ogni item, e una scansione parallela corposa può prosciugare il throughput della tabella sotto al tuo traffico live.

Perché uno Scan sequenziale è lento

Venendo da SQL, una lettura full-table sembra una singola operazione di streaming. In DynamoDB non lo è. I dati della tabella vivono su molte partizioni fisiche, ma un singolo Scan le percorre una alla volta, 1 MB per pagina.

Questo significa che uno Scan normale può attingere solo dal budget di throughput di una partizione in un dato momento — anche se la tabella è distribuita su decine di partizioni con capacità inutilizzata. Più grande è la tabella, più a lungo arranca. (AWS: Scansione parallela)

Suddividi la lettura con Segment e TotalSegments

Una scansione parallela risolve il collo di bottiglia. Scegli un numero di worker, imposti TotalSegments a quel numero e dai a ogni worker un Segment distinto a base zero. Ogni worker lancia il proprio Scan; DynamoDB li serve in modo concorrente.

Worker 0Scan  Segment=0  TotalSegments=4
Worker 1Scan  Segment=1  TotalSegments=4
Worker 2Scan  Segment=2  TotalSegments=4
Worker 3Scan  Segment=3  TotalSegments=4

Ogni worker pagina ancora con LastEvaluatedKey in modo indipendente — possiede il proprio segmento dalla prima all'ultima pagina. L'applicazione ricuce insieme i quattro stream. Ora stai leggendo il throughput di quattro partizioni in una volta invece di una.

Un esempio concreto: l'export notturno

Diciamo che gestisci una tabella di telemetria, sensor-readings. Ogni item è una lettura da un dispositivo sul campo:

PK = "DEVICE#a83f"          (partition key — l'id del dispositivo)
SK = "TS#2026-06-22T03:14"  (sort key — timestamp ISO)
batteryMv  = 3120
tempC      = 41.8
firmwareTag = "fw-7.2.1"

Ogni notte un cron job riversa l'intera tabella su S3 per il data warehouse di analytics. Uno Scan sequenziale di 80 GB impiega ore e intacca a malapena la tua capacità di lettura provisioned. Quindi lo distribuisci su otto worker:

Scan  sensor-readings  Segment=0  TotalSegments=8  ConsistentRead=falseScan  sensor-readings  Segment=7  TotalSegments=8  ConsistentRead=false

Otto worker, otto segmenti, una lettura della tabella circa otto volte più veloce. Se ti servono solo le letture recenti, aggiungi una FilterExpression per scartare i timestamp vecchi prima che le righe vadano sul filo — costruisci e ispeziona quell'espressione nell'Expression Builder:

FilterExpression:  begins_with(SK, :today)

Come DynamoDB assegna gli item ai segmenti

Ecco la parte che inganna le persone. DynamoDB assegna ogni item a un segmento facendo l'hash della sua partition key — non per conteggio righe, non per conteggio byte.

Quindi ogni item che condivide una PK finisce nello stesso segmento. In sensor-readings, tutte le letture per DEVICE#a83f vanno a un solo worker, a prescindere da quanti timestamp ha quel dispositivo o quanto è grande la sua item collection. (AWS: Scansione parallela)

tabella sensor-readingshash della partition keySegment 0DEVICE#a83fDEVICE#1c20Segment 1DEVICE#9be4Segment 2 (vuoto)

La conseguenza: i segmenti sono disuniformi. Un worker potrebbe possedere tre dispositivi chiacchieroni con milioni di letture; un altro potrebbe pescare una fetta vuota. Aumentare TotalSegments non aiuterà se le tue partition key si raggruppano — aggiungi solo worker inattivi in attesa di quello caldo. Una distribuzione uniforme delle chiavi è ciò che fa ripagare il fan-out.

Vedi il costo di lettura prima di eseguirlo

Una scansione parallela è un evento di throughput, non un pranzo gratis. La domanda onesta è "quante unità di lettura costerà leggere tutta questa tabella?" — e DynoTable ti mostra il costo di lettura misurato di uno scan contro la tua tabella reale, segmento per segmento, così che il job notturno non ti sorprenda sulla bolletta.

Insidie e quando non vale la pena

  • La rupe del throughput. Uno scan con TotalSegments alto può consumare l'intera capacità di lettura della tabella in secondi, affamando il traffico live. Su una tabella che serve utenti, limita ogni worker con il parametro Limit o scansiona fuori picco. (AWS: Scansione parallela)
  • È comunque lo strumento sbagliato per un access pattern. Le scansioni parallele sono per job full-table deliberati — export, backfill, migrazioni. Se ne stai cercando una per rispondere a una query ricorrente, è un segnale di modellazione: aggiungi un GSI e fanne una Query.
  • SELECT * in PartiQL è lo stesso scan travestito. Compila in uno Scan sequenziale. Quando ti servono davvero analytics cross-item — un GROUP BY, una JOIN, un'aggregazione — la SQL Workbench di DynoTable le esegue lato client su un set di risultati limitato, invece di martellare la tabella.
  • La coerenza forte raddoppia la bolletta. Uno Scan usa di default letture eventualmente coerenti. Per un export, lascia ConsistentRead=false a meno che non ti serva davvero uno snapshot puntuale nel tempo.

Prossimi passi

Modella le tue chiavi così che le letture quotidiane non richiedano mai uno scan — inizia con single-table design e Query vs Scan. Quando un job full-table è davvero la scelta giusta, prova DynoTable per eseguire una scansione parallela contro le tue tabelle e osservare il costo di lettura in tempo reale.

Aggiornato