Cómo hacer COUNT, SUM y agregar en DynamoDB
DynamoDB tiene exactamente un agregado integrado: contar los ítems coincidentes con
Select=COUNT. No hay SUM, AVG, MIN ni MAX nativos. E incluso el conteo que
sí puedes obtener lee (y factura) cada ítem que contó. Esta guía cubre qué se
admite realmente, las aproximaciones a las que recurre la gente, y cómo ejecutar
COUNT/SUM/AVG reales sobre una tabla cuando los necesitas.
¿Puede DynamoDB hacer SUM, COUNT y funciones de agregado?
En su mayoría, no. El único agregado integrado de DynamoDB es Select=COUNT, que devuelve el número de ítems coincidentes pero aun así lee (y factura) cada ítem. No hay SUM, AVG, MIN ni MAX nativos, y PartiQL tampoco añade ninguno. Para agregados reales con GROUP BY, pliégalos en tu aplicación, mantén un contador, o ejecuta SQL en el SQL Workbench de DynoTable.
Select=COUNTdevuelve el número de ítems coincidentes, pero DynamoDB aún lee cada ítem para producirlo — pagas el costo de lectura completo deScan/Query, no un costo barato de "conteo".- No hay
SUM,AVG,MINniMAXnativos. Las operaciones de lectura de DynamoDB devuelven ítems; no los pliegan en un número. PartiQL tampoco añade agregados. DescribeTable.ItemCountes gratis pero aproximado y se actualiza solo "aproximadamente cada seis horas" — bien para un panel, mal para cualquier cosa exacta.- Para
COUNT/SUM/AVG/MIN/MAXexactos (conGROUP BY), agrega en tu aplicación, mantén un contador, o ejecútalo en el SQL Workbench de DynoTable (más abajo).
Contar ítems: Select=COUNT
Tanto Query como Scan aceptan un parámetro Select. Ponlo en COUNT y la
respuesta lleva los conteos en lugar de los ítems:
aws dynamodb scan \
--table-name Orders \
--select COUNT \
--filter-expression "#s = :open" \
--expression-attribute-names '{"#s":"status"}' \
--expression-attribute-values '{":open":{"S":"OPEN"}}'La respuesta te da dos números (AWS: Counting the items in the results):
Count— "el número de ítems que quedan, después de aplicar una filter expression (si está presente)."ScannedCount— "el número de ítems evaluados, antes de aplicar cualquierScanFilter." Sin filtro,ScannedCountes lo mismo queCount.
Si solo tienes la partition key y necesitas contar duplicados dentro de ella, la
condición + filtro que pasas es exactamente lo que genera el
DynamoDB Expression Builder — los mapas
KeyConditionExpression, FilterExpression y ExpressionAttributeNames/Values de
arriba — sin escapar el JSON a mano.
Dos pegas más que muerden a quienes cuentan tablas grandes:
- El límite de página de 1 MB sigue aplicándose. "If the size of the
Scanresult set is larger than 1 MB,ScannedCountandCountrepresent only a partial count of the total items" (AWS Scan docs). Tienes que paginar conLastEvaluatedKey→ExclusiveStartKeyy mantener un total acumulado para obtener el número real — el mismo bucle cubierto en paginación de DynamoDB. - Un
Queryestrecho le gana a unScan.Select=COUNTen unQuerymide solo los ítems de la partición objetivo, no toda la tabla. Si puedes fijar una partition key (tabla base o un GSI), cuenta allí — es la diferencia de costo Query-vs-Scan aplicada al conteo.
Select=COUNT vs ItemCount (y por qué está desactualizado)
DescribeTable devuelve un ItemCount (y TableSizeBytes) gratis, sin costo de
lectura. La trampa está en la
referencia de la API en sí:
"DynamoDB updates this value approximately every six hours. Recent changes might not
be reflected in this value." Así que puede quedarse muy por detrás del estado real de
tu tabla.
Select=COUNT | DescribeTable.ItemCount | |
|---|---|---|
| Exactitud | Exacto (para el conjunto coincidente) | Aproximado |
| Frescura | En vivo | Actualizado ~cada 6 horas |
| Costo | Lee + factura cada ítem contado | Gratis (metadatos) |
| Puede filtrar / contar un subconjunto | Sí (filter expression) | No — solo tabla entera |
Usa ItemCount para una idea aproximada de "qué tan grande es esta tabla" o un panel.
Usa Select=COUNT cuando necesites un número exacto, filtrado o actual — y acepta el
costo de lectura. Para cualquier cosa realmente en vivo y gratis, lleva tú mismo un
contador (ver Patrones de agregación más abajo).
Por qué no hay SUM/AVG/MIN/MAX nativos
Las operaciones de lectura de DynamoDB devuelven ítems. No hay planificador de
consultas que pliegue un conjunto de resultados en un escalar, así que no hay nada con
qué calcular un SUM o un AVG. Contar es el único pliegue que ofrece la API, vía
Select=COUNT.
PartiQL no cambia esto. La
gramática de SELECT de PartiQL
es SELECT {{expression}} [, …] FROM {{table}}[.{{index}}] [WHERE …] [ORDER BY {{key}} …],
donde la expresión es "a projection formed from the * wildcard or a projection
list of one or more attribute names or document paths." No hay función de agregado ni
cláusula GROUP BY en esa gramática — y ORDER BY toma una {{key}}, documentada
como "a hash key or a sort key to use to order returned results." Cada SELECT de
PartiQL aún se compila a un GetItem, Query o Scan, así que
SELECT SUM(total) FROM "Orders" sencillamente no es expresable. (Más sobre el techo
de PartiQL en PartiQL vs SQL.)
Patrones de agregación (contadores, streams, del lado de la app)
Como DynamoDB no agrega por ti, los patrones establecidos empujan el trabajo a otra parte:
- Ítem contador mantenido. Mantén un ítem dedicado (p. ej.
PK = "STATS#orders") y hazADDa un atributo numérico en cada escritura con unUpdateItem. Leer el agregado es entonces un únicoGetItem— exacto y barato, pero tú eres dueño de la lógica de incremento, su consistencia y la contención si un contador recibe muchos golpes. - DynamoDB Streams → agregador. Habilita un stream y conéctalo a un Lambda que
actualice totales acumulados (conteos, sumas) a medida que cambian los ítems. Según
los AWS Streams docs,
puedes configurar el
StreamViewTypedel stream para que cada registro lleve elNEW_AND_OLD_IMAGES— "both the new and the old images of the item" — suficiente para mantener agregados estiloSUMactualizados sin re-escanear. Los registros del stream están sujetos a una vida de 24 horas ("the stream records within a shard are removed automatically after 24 hours"), así que el consumidor tiene que ir al día. - Pliegue del lado de la app. Pagina por los ítems coincidentes y acumula el
SUM/AVG/MIN/MAXen tu propio código. Correcto, pero lee (y factura) cada ítem cada vez — el mismo perfil de costo queSelect=COUNT, más la transferencia de datos. - Descargar a analítica. Para agregación analítica pesada o ad-hoc, exporta la tabla a S3 y consúltala con Athena, o vuélcala en streaming a un almacén. Según los AWS export-to-S3 docs, exportar "doesn't consume read capacity units" y te permite "perform analytics and complex queries using AWS services such as Athena" — el camino recomendado por AWS una vez que has superado la agregación por petición.
Cada uno cambia simplicidad por contabilidad en tiempo de escritura (contadores,
streams) o por costo en tiempo de lectura (escaneos del lado de la app). Ningún patrón
hace que DynamoDB en sí calcule un SUM gratis. La versión con agrupación de este
compromiso — agregar por clave en lugar de sobre toda la tabla — tiene su propia
guía: DynamoDB GROUP BY.
Ejecutar COUNT/SUM/AVG en el SQL Workbench de DynoTable
Cuando solo necesitas la respuesta — "cuántos pedidos OPEN, y cuál es su total" — sin escribir un bucle de scan paginado ni un Lambda, el SQL Workbench de DynoTable ejecuta agregados reales. Materializa tus tablas a través del motor real Query/Scan de DynamoDB, y luego ejecuta tu SQL completo encima: SQL dentro de las reglas de patrones de acceso 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 DESCEso es COUNT, SUM, AVG, MIN, MAX, GROUP BY y ORDER BY — ninguno de los
cuales DynamoDB o PartiQL pueden expresar — en una sola sentencia. Esta es la misma
cuña analítica que SQL para DynamoDB; para la historia
completa de agrupación mira DynamoDB GROUP BY.
El Workbench es honesto sobre el modelo de acceso de debajo, no un pretend-Postgres:
- Las filas aún vienen a través del Query/Scan real de DynamoDB. Un
GROUP BYsobre una tabla entera sigue siendo unScanpor debajo — el Workbench expone ese costo en lugar de ocultarlo, el mismo compromiso Query-vs-Scan. - Los agregados se ejecutan sobre los atributos escalares materializados después de que las filas aterrizan.
Preguntas frecuentes
¿Puedo contar ítems en DynamoDB sin escanear?
No exactamente. Para un conteo exacto y actual debes leer los ítems —
Select=COUNT aún mide cada ítem contado. Las únicas opciones sin scan son el
aproximado DescribeTable.ItemCount (actualizado ~cada 6 horas) o un ítem contador
que mantengas tú mismo en cada escritura.
¿Cómo cuento ítems por un GSI?
Ejecuta Query (o Scan) contra el índice con Select=COUNT. Contar vía una
partición estrecha de GSI es mucho más barato que escanear la tabla base, porque solo
lees los ítems de esa partición del índice — modela el índice en torno al conteo que
necesitas.
¿Es preciso DescribeTable.ItemCount?
Es aproximado. La
referencia de la API
indica que DynamoDB actualiza ItemCount y TableSizeBytes "approximately every six
hours," y que "recent changes might not be reflected in this value." No lo uses donde
importe un número exacto o en vivo.
¿Puede DynamoDB hacer SUM o AVG?
No de forma nativa, ni en PartiQL — la
gramática de SELECT de PartiQL
no tiene funciones de agregado. Agrega en tu aplicación, mantén un contador
(opcionalmente vía DynamoDB Streams), o ejecuta el SUM/AVG en el SQL Workbench de
DynoTable.
¿Cuál es la diferencia entre Count y ScannedCount?
ScannedCount es cuántos ítems evaluó DynamoDB antes de tu filtro; Count es cuántos
quedan después. Son iguales cuando no hay filter expression. Una brecha grande entre
ambos significa un conteo ineficiente.
¿Necesitas sumar, promediar o agrupar tus datos de DynamoDB sin escribir un bucle de scan? Descarga DynoTable y ejecútalo en una pestaña de Workbench. ¿Primero comparando clientes? Mira cómo se posiciona frente a una GUI sencilla de DynamoDB.