Einsteiger8 Min. Lesezeit

COUNT, SUM und Aggregate in DynamoDB

DynamoDB hat genau ein eingebautes Aggregat: das Zählen passender Items mit Select=COUNT. Es gibt kein natives SUM, AVG, MIN oder MAX. Und selbst die Zählung, die du bekommen kannst, liest (und berechnet) jedes Item, das sie gezählt hat. Dieser Guide behandelt, was tatsächlich unterstützt wird, die Annäherungen, nach denen Leute greifen, und wie du echte COUNT/SUM/AVG über eine Tabelle laufen lässt, wenn du sie brauchst.

Kann DynamoDB SUM, COUNT und Aggregatfunktionen?

Größtenteils nein. DynamoDBs einziges eingebautes Aggregat ist Select=COUNT, das Zählungen passender Items zurückgibt, aber trotzdem jedes Item liest (und berechnet). Es gibt kein natives SUM, AVG, MIN oder MAX, und PartiQL fügt ebenfalls keines hinzu. Für echte Aggregate mit GROUP BY falte sie in deiner App, pflege einen Zähler oder führe SQL in DynoTables Workbench aus.

  • Select=COUNT gibt die Anzahl passender Items zurück, aber DynamoDB liest trotzdem jedes Item, um sie zu erzeugen — du zahlst die vollen Scan/Query-Lesekosten, keine günstigen „Zähl“-Kosten.
  • Es gibt kein natives SUM, AVG, MIN oder MAX. DynamoDBs Leseoperationen geben Items zurück; sie falten sie nicht in eine Zahl. PartiQL fügt ebenfalls keine Aggregate hinzu.
  • DescribeTable.ItemCount ist kostenlos, aber ungefähr und nur „ungefähr alle sechs Stunden“ aktualisiert — in Ordnung für eine Dashboard-Kachel, falsch für alles Exakte.
  • Für exakte COUNT/SUM/AVG/MIN/MAX (mit GROUP BY) aggregiere in deiner App, pflege einen Zähler oder führe es in DynoTables SQL Workbench aus (unten).

Items zählen: Select=COUNT

Sowohl Query als auch Scan akzeptieren einen Select-Parameter. Setze ihn auf COUNT, und die Antwort trägt die Zählungen statt der Items:

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

Die Antwort liefert dir zwei Zahlen (AWS: Counting the items in the results):

  • Count — „die Anzahl der Items, die nach Anwendung eines Filterausdrucks (falls vorhanden) übrig bleiben.“
  • ScannedCount — „die Anzahl der ausgewerteten Items, bevor irgendein ScanFilter angewendet wird.“ Ohne Filter ist ScannedCount dasselbe wie Count.

Wenn du nur den hast und Duplikate darin zählen musst, ist die Condition + der Filter, den du übergibst, genau das, was der DynamoDB Expression Builder generiert — die FilterExpression- und ExpressionAttributeNames/Values-Maps oben, plus die KeyConditionExpression, wenn du innerhalb einer Partition per Query zählst — ohne das JSON von Hand zu escapen.

Zwei weitere Stolperfallen, die Leute beim Zählen großer Tabellen beißen:

  • Das 1-MB-Seitenlimit gilt weiterhin. „Wenn die Größe der Scan-Ergebnismenge größer als 1 MB ist, stellen ScannedCount und Count nur eine teilweise Zählung der Gesamt-Items dar“ (AWS-Scan-Dokumentation). Du musst paginieren, indem du den LastEvaluatedKey jeder Antwort als ExclusiveStartKey der nächsten Anfrage zurückspeist und eine laufende Summe führst, um die echte Zahl zu erhalten — dieselbe Schleife wie in DynamoDB-Pagination.
  • Ein enger Query schlägt einen Scan. Select=COUNT auf einem Query vermisst nur die Items in der anvisierten Partition, nicht die ganze Tabelle. Wenn du einen Partition Key festnageln kannst (Basistabelle oder ein GSI), zähle dort — es ist die Query-vs-Scan-Kostenlücke, angewendet aufs Zählen.

Select=COUNT vs ItemCount (und warum es veraltet ist)

DescribeTable gibt kostenlos einen ItemCount (und TableSizeBytes) zurück, ohne Lesekosten. Der Haken steht in der API-Referenz selbst: „DynamoDB aktualisiert diesen Wert ungefähr alle sechs Stunden. Jüngste Änderungen sind möglicherweise nicht in diesem Wert widergespiegelt.“ Er kann also weit hinter dem tatsächlichen Zustand deiner Tabelle herhinken.

Select=COUNTDescribeTable.ItemCount
ExaktheitExakt (für die passende Menge)Ungefähr
AktualitätLiveAlle ~6 Stunden aktualisiert
KostenLiest + berechnet jedes gezählte ItemKostenlos (Metadaten)
Kann filtern / Teilmenge zählenJa (Filterausdruck)Nein — nur ganze Tabelle

Verwende ItemCount für eine grobe „Wie groß ist diese Tabelle“-Bauchprüfung oder eine Dashboard-Kachel. Verwende Select=COUNT, wenn du eine exakte, gefilterte oder aktuelle Zahl brauchst — und akzeptiere die Lesekosten. Für alles wirklich Live und Kostenlose führe selbst einen Zähler (siehe Aggregationsmuster unten).

Warum es kein natives SUM/AVG/MIN/MAX gibt

DynamoDBs Leseoperationen geben Items zurück. Es gibt keinen Query-Planer, der eine Ergebnismenge in einen Skalar faltet, also gibt es nichts, womit man ein SUM oder AVG berechnen könnte. Zählen ist die einzige Faltung, die die API anbietet, über Select=COUNT.

PartiQL ändert das nicht. Die PartiQL-SELECT-Grammatik ist SELECT {{expression}} [, …] FROM {{table}}[.{{index}}] [WHERE …] [ORDER BY {{key}} …], wobei der Ausdruck „eine Projektion ist, die aus dem *-Platzhalter oder einer Projektionsliste eines oder mehrerer Attributnamen oder Dokumentpfade gebildet wird.“ Es gibt keine Aggregatfunktion und keine GROUP BY-Klausel in dieser Grammatik — und ORDER BY nimmt einen {{key}}, dokumentiert als „einen Hash-Key oder einen Sort-Key, um zurückgegebene Ergebnisse zu ordnen.“ Jedes PartiQL-SELECT kompiliert immer noch zu einem GetItem, Query oder Scan, sodass SELECT SUM(total) FROM "Orders" schlicht nicht ausdrückbar ist. (Mehr zur PartiQL-Obergrenze in PartiQL vs SQL.)

Aggregationsmuster (Zähler, Streams, App-seitig)

Da DynamoDB nicht für dich aggregiert, schieben die etablierten Muster die Arbeit woanders hin:

  • Gepflegtes Zähler-Item. Halte ein eigenes Item (z. B. PK = "STATS#orders") und ADDe bei jedem Schreibvorgang mit einem UpdateItem zu einem numerischen Attribut. Das Lesen des Aggregats ist dann ein einziges GetItem — exakt und günstig, aber du besitzt die Inkrement-Logik, ihre Konsistenz und die Contention, wenn ein Zähler malträtiert wird.
  • , die einen Aggregator speisen. Aktiviere einen Stream und verdrahte ihn mit einer Lambda, die laufende Summen (Zählungen, Summen) aktualisiert, während sich Items ändern. Gemäß der AWS-Streams-Dokumentation kannst du den StreamViewType des Streams so konfigurieren, dass jeder Datensatz die NEW_AND_OLD_IMAGES trägt — „sowohl das neue als auch das alte Abbild des Items“ — genug, um SUM-artige Aggregate ohne erneuten Scan aktuell zu halten. Stream-Datensätze unterliegen einer 24-Stunden-Lebensdauer („die Stream-Datensätze innerhalb eines Shards werden automatisch nach 24 Stunden entfernt“), also muss der Consumer Schritt halten.
  • App-seitige Faltung. Blättere durch die passenden Items und akkumuliere das SUM/AVG/MIN/MAX in deinem eigenen Code. Korrekt, aber es liest (und berechnet) jedes Item jedes Mal — dasselbe Kostenprofil wie Select=COUNT, plus die Datenübertragung.
  • An Analytik auslagern. Für schwere oder Ad-hoc-analytische Aggregation exportiere die Tabelle nach S3 und frage sie mit Athena ab, oder streame sie in ein Warehouse. Gemäß der AWS-Export-nach-S3-Dokumentation „verbraucht der Export keine Read Capacity Units“ und lässt dich „Analytik und komplexe Abfragen mit AWS-Diensten wie Athena durchführen“ — der von AWS empfohlene Weg, sobald du der Aggregation pro Anfrage entwachsen bist.

Jedes tauscht Einfachheit gegen entweder Buchhaltung zur Schreibzeit (Zähler, Streams) oder Kosten zur Lesezeit (App-seitige Scans). Kein Muster bringt DynamoDB selbst dazu, ein SUM kostenlos zu berechnen. Die Gruppierungsvariante dieses Kompromisses — das Aggregieren pro Key statt über die ganze Tabelle — ist ein eigener Guide: DynamoDB GROUP BY.

COUNT/SUM/AVG in DynoTables SQL Workbench ausführen

Wenn du einfach die Antwort brauchst — „wie viele OFFENE Bestellungen, und was ist ihre Gesamtsumme“ — ohne eine paginierende Scan-Schleife oder eine Lambda zu schreiben, führt DynoTables SQL Workbench echte Aggregate aus. Sie materialisiert deine Tabellen durch DynamoDBs tatsächliche Query/Scan-Laufzeit und führt dann ein einziges SELECT darüber aus — Aggregate, GROUP BY, HAVING, DISTINCT: SQL innerhalb von DynamoDBs Zugriffsmuster-Regeln.

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

Das ist COUNT, SUM, AVG, MIN, MAX, GROUP BY und ORDER BY auf einem berechneten Aggregat — nichts davon kann DynamoDB oder PartiQL ausdrücken (PartiQLs ORDER BY ist auf Key-Attribute beschränkt) — in einer Anweisung. Das ist derselbe analytische Keil wie SQL für DynamoDB; für die vollständige Gruppierungsgeschichte siehe DynamoDB GROUP BY.

Die Workbench ist ehrlich über das darunterliegende Zugriffsmodell, kein Möchtegern-Postgres:

  • Die Zeilen kommen weiterhin durch DynamoDBs echtes Query/Scan. Ein GROUP BY über eine ganze Tabelle ist darunter immer noch ein Scan — die Workbench legt diese Kosten offen, statt sie zu verbergen, derselbe Query-vs-Scan-Kompromiss.
  • Aggregate laufen auf den materialisierten skalaren Attributen, nachdem die Zeilen gelandet sind.

FAQ

Kann ich Items in DynamoDB ohne Scan zählen? Nicht ganz. Für eine exakte, aktuelle Zählung musst du die Items lesen — Select=COUNT vermisst weiterhin jedes gezählte Item. Die einzigen scan-losen Optionen sind der ungefähre DescribeTable.ItemCount (alle ~6 Stunden aktualisiert) oder ein Zähler-Item, das du bei jedem Schreibvorgang selbst pflegst.

Wie zähle ich Items über einen GSI? Führe Query (oder Scan) gegen den Index mit Select=COUNT aus. Über eine enge GSI-Partition zu zählen ist weit günstiger als die Basistabelle zu scannen, weil du nur die Items in dieser Index-Partition liest — modelliere den Index um die Zählung, die du brauchst.

Ist DescribeTable.ItemCount genau? Er ist ungefähr. Die API-Referenz besagt, dass DynamoDB ItemCount und TableSizeBytes „ungefähr alle sechs Stunden“ aktualisiert und „jüngste Änderungen möglicherweise nicht in diesem Wert widergespiegelt sind.“ Verwende ihn nicht, wo eine exakte oder Live-Zahl zählt.

Kann DynamoDB SUM oder AVG? Nicht nativ, und nicht in PartiQL — die PartiQL-SELECT-Grammatik hat keine Aggregatfunktionen. Aggregiere in deiner Anwendung, pflege einen Zähler (optional über DynamoDB Streams) oder führe das SUM/AVG in DynoTables SQL Workbench aus.

Was ist der Unterschied zwischen Count und ScannedCount? ScannedCount ist, wie viele Items DynamoDB vor deinem Filter ausgewertet hat; Count ist, wie viele danach übrig bleiben. Sie sind gleich, wenn es keinen Filterausdruck gibt. Eine große Lücke zwischen ihnen bedeutet eine ineffiziente Zählung.


Musst du deine DynamoDB-Daten summieren, mitteln oder gruppieren, ohne eine Scan-Schleife zu schreiben? Lade DynoTable herunter und führe es in einem Workbench-Tab aus. Vergleichst du erst die Clients? Sieh, wo es gegen eine reine DynamoDB-GUI landet.

Aktualisiert