COUNT, SUM et agrégats dans DynamoDB
DynamoDB dispose d'exactement un agrégat intégré : compter les items correspondants avec
Select=COUNT. Il n'y a pas de SUM, AVG, MIN ou 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 on se tourne, et comment exécuter de vrais
COUNT/SUM/AVG sur une table quand tu en as besoin.
DynamoDB peut-il faire SUM, COUNT et des fonctions d'agrégation ?
Essentiellement 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 ou MAX natif, et PartiQL n'en ajoute aucun non plus. Pour de vrais agrégats avec GROUP BY, replie-les dans ton application, maintiens un compteur, ou exécute du SQL dans le Workbench de DynoTable.
Select=COUNTrenvoie le nombre d'items correspondants, mais DynamoDB lit quand même chaque item pour le produire — tu paies le plein coût de lecture d'unScan/Query, pas un coût de « comptage » bon marché.- Il n'y a pas de
SUM,AVG,MINouMAXnatif. Les opérations de lecture de DynamoDB renvoient des items ; elles ne les replient pas en un nombre. PartiQL n'ajoute pas d'agrégats non plus. DescribeTable.ItemCountest gratuit mais approximatif et mis à jour seulement « environ toutes les six heures » — bien pour une tuile de tableau de bord, faux pour tout ce qui doit être exact.- Pour des
COUNT/SUM/AVG/MIN/MAXexacts (avecGROUP BY), agrège dans ton application, maintiens un compteur, ou exécute-les dans le SQL Workbench de DynoTable (ci-dessous).
Compter des items : Select=COUNT
Query et Scan acceptent tous deux un paramètre Select. Règle-le sur 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 : Compter les items dans les résultats) :
Count— « le nombre d'items qui restent, après l'application d'une expression de filtre (si présente). »ScannedCount— « le nombre d'items évalués, avant l'application d'unScanFilter. » Sans filtre,ScannedCountest identique àCount.
Si tu n'as que la et que tu dois compter les doublons en son sein, la
condition + le filtre que tu passes sont exactement ce que le
Générateur d'expressions DynamoDB génère — la
FilterExpression et les maps ExpressionAttributeNames/Values ci-dessus, plus la
KeyConditionExpression quand tu comptes au sein d'une partition via Query — sans
échapper le JSON à la main.
Deux autres pièges qui touchent ceux 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
Scanest supérieure à 1 Mo,ScannedCountetCountne représentent qu'un comptage partiel du total des items » (documentation Scan d'AWS). Tu dois paginer en réinjectant leLastEvaluatedKeyde chaque réponse commeExclusiveStartKeyde la requête suivante, en tenant un total courant pour obtenir le vrai nombre — la même boucle couverte dans la pagination DynamoDB. - Une
Queryétroite bat unScan.Select=COUNTsur uneQueryne métre que les items de la partition ciblée, pas toute la table. Si tu peux fixer une clé de partition (table de base ou 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 un TableSizeBytes) gratuitement, sans
coût de lecture. Le hic est dans la
référence d'API elle-même :
« DynamoDB met à jour cette valeur environ toutes les six heures. Les changements récents pourraient ne pas
être reflétés dans cette valeur. » Elle peut donc être bien en retard sur l'état réel de ta table.
Select=COUNT | DescribeTable.ItemCount | |
|---|---|---|
| Exactitude | Exact (pour l'ensemble correspondant) | Approximatif |
| Fraîcheur | En direct | Mis à jour ~toutes les 6 heures |
| Coût | Lit + facture chaque item compté | Gratuit (métadonnées) |
| Peut filtrer / compter un sous-ensemble | Oui (expression de filtre) | Non — toute la table uniquement |
Utilise ItemCount pour une estimation approximative « 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 courant — et accepte
le coût de lecture. Pour quelque chose de vraiment en direct et gratuit, suis un compteur toi-même
(voir Motifs 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. Le comptage est
le seul repli que l'API offre, via Select=COUNT.
PartiQL n'y change rien. 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 d'une liste de
projection d'un ou plusieurs noms d'attribut ou chemins de document. » Il n'y a pas de fonction
d'agrégation ni de 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 toujours en un GetItem, une Query ou un Scan, donc
SELECT SUM(total) FROM "Orders" n'est tout simplement pas exprimable. (Plus sur le plafond de PartiQL
dans PartiQL vs SQL.)
Motifs d'agrégation (compteurs, streams, côté application)
Puisque DynamoDB n'agrège pas pour toi, les motifs établis poussent le travail ailleurs :
- Item compteur maintenu. Garde un item dédié (par ex.
PK = "STATS#orders") et fais unADDsur un attribut numérique à chaque écriture avec unUpdateItem. Lire l'agrégat n'est alors qu'un seulGetItem— 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é. - alimentant un agrégateur. Active un stream et relie-le à une Lambda qui
met à jour des totaux courants (comptes, sommes) à mesure que les items changent. D'après la
documentation Streams d'AWS,
tu peux configurer le
StreamViewTypedu stream pour que chaque enregistrement porte lesNEW_AND_OLD_IMAGES— « à la fois la nouvelle et l'ancienne image de l'item » — de quoi garder les agrégats de typeSUMà jour sans re-balayer. 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. - Repli côté application. Parcours les items correspondants et accumule le
SUM/AVG/MIN/MAXdans ton propre code. Correct, mais cela lit (et facture) chaque item à chaque fois — le même profil de coût queSelect=COUNT, plus le transfert de données. - Décharger vers l'analytique. Pour une agrégation analytique lourde ou ad-hoc, exporte la table vers S3 et interroge-la avec Athena, ou envoie-la en flux dans un entrepôt. D'après la documentation export-vers-S3 d'AWS, l'export « ne consomme pas d'unités de capacité de lecture » et te permet d'« effectuer des analyses et des requêtes complexes à l'aide de services AWS tels qu'Athena » — la voie recommandée par AWS une fois que tu as dépassé l'agrégation par requête.
Chacun échange la simplicité contre soit une comptabilité au moment de l'écriture (compteurs, streams), soit un
coût au moment de la lecture (scans côté application). Aucun motif 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 toute la table — a son propre guide :
DynamoDB GROUP BY.
Exécuter COUNT/SUM/AVG dans le SQL Workbench 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 SQL Workbench de DynoTable
exécute de vrais agrégats. Il matérialise tes tables à travers le runtime Query/Scan
réel de DynamoDB, puis exécute un seul SELECT par-dessus — agrégats, GROUP BY,
HAVING, DISTINCT : du SQL dans le respect des 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 DESCCela fait COUNT, SUM, AVG, MIN, MAX, GROUP BY et ORDER BY sur un
agrégat calculé — aucun de ceux-ci ne peut être exprimé par DynamoDB ni PartiQL (l'ORDER BY de
PartiQL est limité aux attributs de clé) — en une seule instruction. C'est le même
levier analytique que SQL pour DynamoDB ; pour l'histoire complète du
groupement, voir DynamoDB GROUP BY.
Le Workbench est honnête sur le modèle d'accès sous-jacent, ce n'est pas un faux Postgres :
- Les lignes passent toujours par le vrai Query/Scan de DynamoDB. Un
GROUP BYsur toute une table reste unScanen dessous — le Workbench fait remonter 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 après l'atterrissage des lignes.
FAQ
Puis-je compter des items dans DynamoDB sans balayer ?
Pas vraiment. Pour un compte exact et courant, tu dois lire les items —
Select=COUNT métre quand même chaque item compté. Les seules options sans scan sont le
DescribeTable.ItemCount approximatif (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 une Query (ou un Scan) sur l'index avec Select=COUNT. Compter via une
partition de GSI étroite est bien moins coûteux que de balayer la table de base, car tu ne
lis que les items de cette partition d'index — modélise l'index autour du compte dont tu as besoin.
DescribeTable.ItemCount est-il exact ?
Il est approximatif. La
référence d'API
indique que DynamoDB met à jour ItemCount et TableSizeBytes « environ toutes les six
heures », et que « les changements récents pourraient 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 pas de fonctions d'agrégation. Agrège dans ton application, maintiens un compteur
(éventuellement via DynamoDB Streams), ou exécute le SUM/AVG dans le SQL
Workbench 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 signale un comptage inefficace.
Besoin de sommer, moyenner ou grouper tes données DynamoDB sans écrire de boucle de scan ? Télécharge DynoTable et exécute-le dans un onglet Workbench. Tu compares d'abord les clients ? Vois où il se situe face à une interface graphique DynamoDB classique.