Principiante9 min di lettura

Come fare COUNT, SUM e aggregare in DynamoDB

DynamoDB ha esattamente un aggregato integrato: contare gli item corrispondenti con Select=COUNT. Non c'è alcun SUM, AVG, MIN o MAX nativo. E persino il conteggio che puoi ottenere legge (e fattura) ogni item che ha contato. Questa guida copre cosa è effettivamente supportato, le approssimazioni a cui le persone ricorrono, e come eseguire veri COUNT/SUM/AVG su una tabella quando ti servono.

DynamoDB può fare SUM, COUNT e funzioni di aggregazione?

Per lo più no. L'unico aggregato integrato di DynamoDB è Select=COUNT, che restituisce il numero di item corrispondenti ma legge comunque (e fattura) ogni item. Non esiste alcun SUM, AVG, MIN o MAX nativo, e nemmeno PartiQL ne aggiunge. Per veri aggregati con GROUP BY, aggregali nella tua app, mantieni un contatore, o esegui SQL nel Workbench di DynoTable.

  • Select=COUNT restituisce il numero di item corrispondenti, ma DynamoDB legge comunque ogni item per produrlo — paghi l'intero costo di lettura Scan/Query, non un costo "count" economico.
  • Non c'è alcun SUM, AVG, MIN o MAX nativo. Le operazioni di lettura di DynamoDB restituiscono item; non li riducono in un numero. Nemmeno PartiQL aggiunge gli aggregati.
  • DescribeTable.ItemCount è gratuito ma approssimato e aggiornato solo "approssimativamente ogni sei ore" — va bene per un riquadro di dashboard, sbagliato per qualunque cosa esatta.
  • Per COUNT/SUM/AVG/MIN/MAX esatti (con GROUP BY), aggrega nella tua app, mantieni un contatore, o eseguilo nel Workbench SQL di DynoTable (sotto).

Contare gli item: Select=COUNT

Sia Query che Scan accettano un parametro Select. Impostalo a COUNT e la risposta porta i conteggi invece degli item:

aws dynamodb scan \
  --table-name Orders \
  --select COUNT \
  --filter-expression "#s = :open" \
  --expression-attribute-names '{"#s":"status"}' \
  --expression-attribute-values '{":open":{"S":"OPEN"}}'

La risposta ti dà due numeri (AWS: Counting the items in the results):

  • Count — "il numero di item che rimangono, dopo che è stata applicata un'espressione di filtro (se presente)."
  • ScannedCount — "il numero di item valutati, prima che venga applicato qualunque ScanFilter." Senza filtro, ScannedCount è uguale a Count.

Se hai solo la partition key e devi contare i duplicati al suo interno, la condizione + il filtro che passi sono esattamente ciò che il DynamoDB Expression Builder genera — le mappe KeyConditionExpression, FilterExpression ed ExpressionAttributeNames/Values qui sopra — senza dover fare l'escape manuale del JSON.

Altri due tranelli che colpiscono chi conta tabelle grandi:

  • Il limite di pagina da 1 MB si applica comunque. "Se la dimensione del set di risultati dello Scan è maggiore di 1 MB, ScannedCount e Count rappresentano solo un conteggio parziale del totale degli item" (documentazione Scan di AWS). Devi paginare con LastEvaluatedKeyExclusiveStartKey e tenere un totale progressivo per ottenere il numero reale — lo stesso ciclo trattato in paginazione DynamoDB.
  • Una Query ristretta batte uno Scan. Select=COUNT su una Query contabilizza solo gli item nella partizione mirata, non l'intera tabella. Se puoi fissare una partition key (tabella base o un GSI), conta lì — è il divario di costo Query-vs-Scan applicato al conteggio.

Select=COUNT vs ItemCount (e perché è obsoleto)

DescribeTable restituisce un ItemCount (e TableSizeBytes) gratuitamente, senza costo di lettura. Il problema è nello stesso riferimento API: "DynamoDB aggiorna questo valore approssimativamente ogni sei ore. Le modifiche recenti potrebbero non essere riflesse in questo valore." Quindi può rimanere molto indietro rispetto allo stato effettivo della tua tabella.

Select=COUNTDescribeTable.ItemCount
EsattezzaEsatto (per l'insieme corrispondente)Approssimato
FreschezzaLiveAggiornato ~ogni 6 ore
CostoLegge + fattura ogni item contatoGratuito (metadati)
Può filtrare / contare un sottoinsiemeSì (espressione di filtro)No — solo intera tabella

Usa ItemCount per una stima approssimativa di "quanto è grande questa tabella" o un riquadro di dashboard. Usa Select=COUNT quando ti serve un numero esatto, filtrato o attuale — e accetta il costo di lettura. Per qualcosa di davvero live e gratuito, traccia tu stesso un contatore (vedi Pattern di aggregazione sotto).

Perché non c'è alcun SUM/AVG/MIN/MAX nativo

Le operazioni di lettura di DynamoDB restituiscono item. Non c'è alcun query planner per ridurre un insieme di risultati in uno scalare, quindi non c'è nulla con cui calcolare un SUM o un AVG. Il conteggio è l'unica riduzione che l'API offre, tramite Select=COUNT.

PartiQL non cambia questo. La grammatica SELECT di PartiQL è SELECT {{expression}} [, …] FROM {{table}}[.{{index}}] [WHERE …] [ORDER BY {{key}} …], dove l'espressione è "una proiezione formata dal carattere jolly * o un elenco di proiezione di uno o più nomi di attributo o percorsi di documento." Non c'è alcuna funzione di aggregazione e nessuna clausola GROUP BY in quella grammatica — e ORDER BY accetta una {{key}}, documentata come "una hash key o una sort key da usare per ordinare i risultati restituiti." Ogni SELECT PartiQL si compila comunque in un GetItem, Query o Scan, quindi SELECT SUM(total) FROM "Orders" semplicemente non è esprimibile. (Altro sul limite di PartiQL in PartiQL vs SQL.)

Pattern di aggregazione (contatori, stream, lato app)

Dato che DynamoDB non aggrega per te, i pattern consolidati spingono il lavoro altrove:

  • Item contatore mantenuto. Tieni un item dedicato (ad es. PK = "STATS#orders") e fai ADD a un attributo numerico a ogni scrittura con un UpdateItem. Leggere l'aggregato è poi un singolo GetItem — esatto ed economico, ma sei tu a possedere la logica di incremento, la sua consistenza e la contesa se un contatore viene martellato.
  • DynamoDB Streams → aggregatore. Abilita uno stream e collegalo a una Lambda che aggiorna i totali progressivi (conteggi, somme) mentre gli item cambiano. Secondo la documentazione Streams di AWS, puoi configurare lo StreamViewType dello stream in modo che ogni record porti il NEW_AND_OLD_IMAGES — "sia la nuova sia la vecchia immagine dell'item" — abbastanza da mantenere aggiornati gli aggregati in stile SUM senza ri-scansionare. I record di stream sono soggetti a una durata di 24 ore ("i record di stream all'interno di uno shard vengono rimossi automaticamente dopo 24 ore"), quindi il consumatore deve stare al passo.
  • Riduzione lato app. Pagina attraverso gli item corrispondenti e accumula il SUM/AVG/MIN/MAX nel tuo codice. Corretto, ma legge (e fattura) ogni item ogni volta — lo stesso profilo di costo di Select=COUNT, più il trasferimento dei dati.
  • Scaricare sull'analisi. Per aggregazioni analitiche pesanti o ad hoc, esporta la tabella su S3 e interrogala con Athena, oppure trasmettila in un warehouse. Secondo la documentazione export-to-S3 di AWS, l'esportazione "non consuma read capacity unit" e ti permette di "eseguire analisi e query complesse usando servizi AWS come Athena" — il percorso raccomandato da AWS una volta superata l'aggregazione per richiesta.

Ognuno scambia la semplicità con la contabilità a tempo di scrittura (contatori, stream) o con il costo a tempo di lettura (scan lato app). Nessun pattern fa sì che DynamoDB stesso calcoli un SUM gratuitamente. La versione con raggruppamento di questo compromesso — aggregare per chiave anziché sull'intera tabella — ha la sua guida dedicata: DynamoDB GROUP BY.

Eseguire COUNT/SUM/AVG nel Workbench SQL di DynoTable

Quando ti serve solo la risposta — "quanti ordini OPEN, e qual è il loro totale" — senza scrivere un ciclo di scan con paginazione o una Lambda, il Workbench SQL di DynoTable esegue veri aggregati. Materializza le tue tabelle attraverso l'effettivo runtime Query/Scan di DynamoDB, poi esegue il tuo SQL completo sopra: SQL all'interno delle regole di access pattern di DynamoDB.

-- Runs in the DynoTable Workbench (NOT in PartiQL):
SELECT status,
       COUNT(*)        AS orders,
       SUM(total)      AS revenue,
       AVG(total)      AS avg_order,
       MIN(total)      AS smallest,
       MAX(total)      AS largest
FROM orders
GROUP BY status
ORDER BY revenue DESC

Quelli sono COUNT, SUM, AVG, MIN, MAX, GROUP BY e ORDER BY — nessuno dei quali DynamoDB o PartiQL può esprimere — in una sola istruzione. Questo è lo stesso cuneo analitico di SQL per DynamoDB; per la storia completa sul raggruppamento vedi DynamoDB GROUP BY.

Il Workbench è onesto sul modello di accesso sottostante, non finge di essere Postgres:

  • Le righe arrivano comunque attraverso il vero Query/Scan di DynamoDB. Un GROUP BY su un'intera tabella è comunque uno Scan sotto — il Workbench fa emergere quel costo invece di nasconderlo, lo stesso compromesso Query-vs-Scan.
  • Gli aggregati vengono eseguiti sugli attributi scalari materializzati dopo che le righe sono arrivate.

FAQ

Posso contare gli item in DynamoDB senza scansionare? Non proprio. Per un conteggio esatto e attuale devi leggere gli item — Select=COUNT contabilizza comunque ogni item contato. Le uniche opzioni senza scan sono l'approssimato DescribeTable.ItemCount (aggiornato ~ogni 6 ore) o un item contatore che mantieni tu stesso a ogni scrittura.

Come conto gli item per un GSI? Esegui una Query (o uno Scan) sull'indice con Select=COUNT. Contare tramite una partizione GSI ristretta è molto più economico che scansionare la tabella base, perché leggi solo gli item in quella partizione dell'indice — modella l'indice attorno al conteggio che ti serve.

DescribeTable.ItemCount è accurato? È approssimato. Il riferimento API afferma che DynamoDB aggiorna ItemCount e TableSizeBytes "approssimativamente ogni sei ore", e "le modifiche recenti potrebbero non essere riflesse in questo valore." Non usarlo dove conta un numero esatto o live.

DynamoDB può fare SUM o AVG? Non nativamente, e non in PartiQL — la grammatica SELECT di PartiQL non ha funzioni di aggregazione. Aggrega nella tua applicazione, mantieni un contatore (opzionalmente tramite DynamoDB Streams), o esegui il SUM/AVG nel Workbench SQL di DynoTable.

Qual è la differenza tra Count e ScannedCount? ScannedCount è quanti item DynamoDB ha valutato prima del tuo filtro; Count è quanti ne rimangono dopo. Sono uguali quando non c'è alcuna espressione di filtro. Un grande divario tra loro significa un conteggio inefficiente.


Hai bisogno di sommare, fare la media o raggruppare i tuoi dati DynamoDB senza scrivere un ciclo di scan? Scarica DynoTable ed eseguilo in una scheda Workbench. Stai confrontando i client prima? Vedi come si colloca rispetto a una GUI DynamoDB semplice.

Aggiornato