Débutant10 min de lecture

Comment faire COUNT, SUM et agréger dans DynamoDB

DynamoDB possède exactement un agrégat intégré : compter les items correspondants avec Select=COUNT. Il n'y a pas de SUM, AVG, MIN ni MAX natif. Et même le compte que tu peux obtenir lit (et facture) chaque item qu'il a compté. Ce guide couvre ce qui est réellement pris en charge, les approximations vers lesquelles les gens se tournent, et comment exécuter un vrai COUNT/SUM/AVG sur une table quand tu en as besoin.

DynamoDB peut-il faire SUM, COUNT et des fonctions d'agrégat ?

Le plus souvent, non. Le seul agrégat intégré de DynamoDB est Select=COUNT, qui renvoie le nombre d'items correspondants mais lit (et facture) quand même chaque item. Il n'y a pas de SUM, AVG, MIN ni MAX natif, et PartiQL n'en ajoute aucun non plus. Pour de vrais agrégats avec GROUP BY, agrège-les dans ton application, maintiens un compteur, ou exécute du SQL dans le Workbench de DynoTable.

  • Select=COUNT renvoie le nombre d'items correspondants, mais DynamoDB lit quand même chaque item pour le produire — tu paies le coût de lecture complet du Scan/Query, pas un coût de « comptage » bon marché.
  • Il n'y a pas de SUM, AVG, MIN ni MAX natif. Les opérations de lecture de DynamoDB renvoient des items ; elles ne les replient pas en un nombre. PartiQL n'ajoute pas non plus d'agrégats.
  • DescribeTable.ItemCount est gratuit mais approximatif et mis à jour uniquement « approximativement toutes les six heures » — parfait pour une tuile de tableau de bord, faux pour quoi que ce soit d'exact.
  • Pour un COUNT/SUM/AVG/MIN/MAX exact (avec GROUP BY), agrège dans ton application, maintiens un compteur, ou exécute-le dans le Workbench SQL de DynoTable (ci-dessous).

Compter des items : Select=COUNT

Query et Scan acceptent tous deux un paramètre Select. Mets-le à COUNT et la réponse porte les comptes au lieu des items :

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

La réponse te donne deux nombres (AWS : Counting the items in the results) :

  • Count — « le nombre d'items qui restent, après l'application d'une expression de filtre (le cas échéant). »
  • ScannedCount — « le nombre d'items évalués, avant l'application de tout ScanFilter. » Sans filtre, ScannedCount est identique à Count.

Si tu n'as que la clé de partition et que tu dois compter les doublons qu'elle contient, la condition + le filtre que tu transmets sont exactement ce que génère le DynamoDB Expression Builder — les maps KeyConditionExpression, FilterExpression et ExpressionAttributeNames/Values ci-dessus — sans échapper le JSON à la main.

Deux autres pièges qui mordent les gens qui comptent de grandes tables :

  • La limite de page de 1 Mo s'applique toujours. « Si la taille de l'ensemble de résultats du Scan dépasse 1 Mo, ScannedCount et Count ne représentent qu'un comptage partiel du total des items » (doc AWS Scan). Tu dois paginer avec LastEvaluatedKeyExclusiveStartKey et tenir un total courant pour obtenir le vrai nombre — la même boucle couverte dans la pagination DynamoDB.
  • Un Query étroit bat un Scan. Select=COUNT sur un Query ne mesure que les items de la partition ciblée, pas la table entière. Si tu peux fixer une clé de partition (table de base ou un GSI), compte là — c'est l'écart de coût Query vs Scan appliqué au comptage.

Select=COUNT vs ItemCount (et pourquoi il est périmé)

DescribeTable renvoie un ItemCount (et TableSizeBytes) gratuitement, sans coût de lecture. Le hic est dans la référence de l'API elle-même : « DynamoDB met à jour cette valeur environ toutes les six heures. Les changements récents peuvent ne pas être reflétés dans cette valeur. » Il peut donc être très en retard sur l'état réel de ta table.

Select=COUNTDescribeTable.ItemCount
ExactitudeExact (pour l'ensemble correspondant)Approximatif
FraîcheurEn directMis à jour ~toutes les 6 heures
CoûtLit + facture chaque item comptéGratuit (métadonnées)
Peut filtrer / compter un sous-ensembleOui (expression de filtre)Non — table entière uniquement

Utilise ItemCount pour une vérification approximative du genre « quelle est la taille de cette table » ou une tuile de tableau de bord. Utilise Select=COUNT quand tu as besoin d'un nombre exact, filtré ou actuel — et accepte le coût de lecture. Pour quelque chose de vraiment en direct et gratuit, suis un compteur toi-même (voir Schémas d'agrégation ci-dessous).

Pourquoi il n'y a pas de SUM/AVG/MIN/MAX natif

Les opérations de lecture de DynamoDB renvoient des items. Il n'y a pas de planificateur de requêtes pour replier un ensemble de résultats en un scalaire, donc il n'y a rien pour calculer un SUM ou un AVG. Compter est le seul repliement que l'API propose, via Select=COUNT.

PartiQL ne change rien à cela. La grammaire SELECT de PartiQL est SELECT {{expression}} [, …] FROM {{table}}[.{{index}}] [WHERE …] [ORDER BY {{key}} …], où l'expression est « une projection formée à partir du joker * ou une liste de projection d'un ou plusieurs noms d'attribut ou chemins de document. » Il n'y a aucune fonction d'agrégat et aucune clause GROUP BY dans cette grammaire — et ORDER BY prend une {{key}}, documentée comme « une clé de hachage ou une clé de tri à utiliser pour ordonner les résultats renvoyés. » Chaque SELECT PartiQL se compile encore en un GetItem, Query ou Scan, donc SELECT SUM(total) FROM "Orders" n'est tout simplement pas exprimable. (Plus de détails sur le plafond de PartiQL dans PartiQL vs SQL.)

Schémas d'agrégation (compteurs, streams, côté application)

Comme DynamoDB n'agrège pas à ta place, les schémas établis poussent le travail ailleurs :

  • Item compteur maintenu. Garde un item dédié (par ex. PK = "STATS#orders") et utilise ADD sur un attribut numérique à chaque écriture avec un UpdateItem. Lire l'agrégat n'est alors qu'un seul GetItem — exact et bon marché, mais tu es responsable de la logique d'incrémentation, de sa cohérence et de la contention si un compteur est martelé.
  • DynamoDB Streams → agrégateur. Active un stream et relie-le à une Lambda qui met à jour les totaux courants (comptes, sommes) au fil des changements d'items. Selon la doc AWS Streams, tu peux configurer le StreamViewType du stream pour que chaque enregistrement porte NEW_AND_OLD_IMAGES — « à la fois la nouvelle et l'ancienne image de l'item » — suffisant pour garder à jour des agrégats de type SUM sans re-scanner. Les enregistrements de stream sont soumis à une durée de vie de 24 heures (« les enregistrements de stream d'un shard sont supprimés automatiquement après 24 heures »), donc le consommateur doit suivre le rythme.
  • Repliement côté application. Parcours les items correspondants et accumule le SUM/AVG/MIN/MAX dans ton propre code. Correct, mais il lit (et facture) chaque item à chaque fois — le même profil de coût que Select=COUNT, plus le transfert de données.
  • Déporter vers l'analytique. Pour une agrégation analytique lourde ou ad hoc, exporte la table vers S3 et interroge-la avec Athena, ou diffuse-la dans un entrepôt. Selon la doc AWS export-to-S3, l'export « ne consomme pas d'unités de capacité de lecture » et te permet d'« effectuer des analyses et des requêtes complexes en utilisant des services AWS tels qu'Athena » — le chemin recommandé par AWS une fois que tu as dépassé l'agrégation par requête.

Chacun échange la simplicité contre soit de la comptabilité au moment de l'écriture (compteurs, streams), soit un coût au moment de la lecture (scans côté application). Aucun schéma ne fait calculer un SUM à DynamoDB lui-même gratuitement. La version groupée de ce compromis — agréger par clé plutôt que sur la table entière — fait l'objet de son propre guide : DynamoDB GROUP BY.

Exécuter COUNT/SUM/AVG dans le Workbench SQL de DynoTable

Quand tu as juste besoin de la réponse — « combien de commandes OPEN, et quel est leur total » — sans écrire une boucle de scan paginée ni une Lambda, le Workbench SQL de DynoTable exécute de vrais agrégats. Il matérialise tes tables à travers le véritable moteur Query/Scan de DynamoDB, puis exécute ton SQL complet par-dessus : du SQL dans les règles d'accès de 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

Voilà COUNT, SUM, AVG, MIN, MAX, GROUP BY et ORDER BY — aucun de ces éléments que DynamoDB ou PartiQL ne peut exprimer — en une seule instruction. C'est le même levier analytique que SQL pour DynamoDB ; pour l'histoire complète du groupement, vois DynamoDB GROUP BY.

Le Workbench est honnête à propos du modèle d'accès sous-jacent, ce n'est pas un faux-Postgres :

  • Les lignes passent toujours par le véritable Query/Scan de DynamoDB. Un GROUP BY sur une table entière reste un Scan en dessous — le Workbench fait apparaître ce coût plutôt que de le cacher, le même compromis Query vs Scan.
  • Les agrégats s'exécutent sur les attributs scalaires matérialisés une fois que les lignes ont atterri.

FAQ

Puis-je compter des items dans DynamoDB sans scanner ? Pas exactement. Pour un compte exact et actuel, tu dois lire les items — Select=COUNT mesure quand même chaque item compté. Les seules options sans scan sont l'approximatif DescribeTable.ItemCount (mis à jour ~toutes les 6 heures) ou un item compteur que tu maintiens toi-même à chaque écriture.

Comment compter des items par un GSI ? Exécute Query (ou Scan) contre l'index avec Select=COUNT. Compter via une partition de GSI étroite est bien moins coûteux que scanner la table de base, parce que tu ne lis que les items de cette partition d'index — modélise l'index autour du comptage dont tu as besoin.

DescribeTable.ItemCount est-il exact ? Il est approximatif. La référence de l'API indique que DynamoDB met à jour ItemCount et TableSizeBytes « environ toutes les six heures », et que « les changements récents peuvent ne pas être reflétés dans cette valeur. » Ne l'utilise pas là où un nombre exact ou en direct compte.

DynamoDB peut-il faire SUM ou AVG ? Pas nativement, et pas en PartiQL — la grammaire SELECT de PartiQL n'a aucune fonction d'agrégat. Agrège dans ton application, maintiens un compteur (éventuellement via DynamoDB Streams), ou exécute le SUM/AVG dans le Workbench SQL de DynoTable.

Quelle est la différence entre Count et ScannedCount ? ScannedCount est le nombre d'items que DynamoDB a évalués avant ton filtre ; Count est le nombre qui reste après. Ils sont égaux quand il n'y a pas d'expression de filtre. Un grand écart entre eux signifie un comptage inefficace.


Besoin de sommer, moyenner ou grouper tes données DynamoDB sans écrire une boucle de scan ? Télécharge DynoTable et exécute-le dans un onglet Workbench. Tu compares d'abord les clients ? Vois comment il se positionne face à une GUI DynamoDB classique.

Mis à jour