Principiante9 min de lectura

Cómo hacer COUNT, SUM y agregados en DynamoDB

DynamoDB tiene exactamente un agregado incorporado: contar los elementos que coinciden con Select=COUNT. No hay SUM, AVG, MIN ni MAX nativos. E incluso el recuento que puedes obtener lee (y factura) cada elemento que contó. Esta guía cubre lo que realmente se admite, 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 agregación?

Mayormente no. El único agregado incorporado de DynamoDB es Select=COUNT, que devuelve recuentos de elementos coincidentes pero aún lee (y factura) cada elemento. No hay SUM, AVG, MIN ni MAX nativos, y PartiQL tampoco añade ninguno. Para agregados reales con GROUP BY, agrégalos en tu aplicación, mantén un contador o ejecuta SQL en el Workbench de DynoTable.

  • Select=COUNT devuelve el número de elementos coincidentes, pero DynamoDB aún lee cada elemento para producirlo — pagas el costo de lectura completo del Scan/Query, no un costo de "recuento" barato.
  • No hay SUM, AVG, MIN ni MAX nativos. Las operaciones de lectura de DynamoDB devuelven elementos; no los pliegan en un número. PartiQL tampoco añade agregados.
  • DescribeTable.ItemCount es gratis pero aproximado y se actualiza solo "aproximadamente cada seis horas" — bien para un mosaico de panel, incorrecto para cualquier cosa exacta.
  • Para COUNT/SUM/AVG/MIN/MAX exactos (con GROUP BY), agrega en tu aplicación, mantén un contador o ejecútalo en el SQL Workbench de DynoTable (abajo).

Contar elementos: Select=COUNT

Tanto Query como Scan aceptan un parámetro Select. Ponlo en COUNT y la respuesta lleva los recuentos en lugar de los elementos:

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: Contar los elementos en los resultados):

  • Count — "el número de elementos que quedan, después de aplicar una expresión de filtro (si está presente)".
  • ScannedCount — "el número de elementos evaluados, antes de aplicar cualquier ScanFilter". Sin filtro, ScannedCount es igual a Count.

Si solo tienes la y necesitas contar duplicados dentro de ella, la condición + filtro que pasas es exactamente lo que genera el Generador de expresiones de DynamoDB — la FilterExpression y los mapas ExpressionAttributeNames/Values de arriba, más la KeyConditionExpression cuando cuentas dentro de una partición mediante Query — sin escapar el JSON a mano.

Dos escollos más que muerden a quienes cuentan tablas grandes:

  • El límite de página de 1 MB sigue aplicando. "Si el tamaño del conjunto de resultados del Scan es mayor que 1 MB, ScannedCount y Count representan solo un recuento parcial del total de elementos" (documentos de Scan de AWS). Tienes que paginar retroalimentando el LastEvaluatedKey de cada respuesta como el ExclusiveStartKey de la siguiente solicitud, manteniendo un total acumulado para obtener el número real — el mismo bucle cubierto en paginación de DynamoDB.
  • Una Query estrecha supera a un Scan. Select=COUNT en una Query contabiliza solo los elementos de la partición objetivo, no de toda la tabla. Si puedes fijar una clave de partición (tabla base o un GSI), cuenta ahí — es la brecha de costo Query frente a Scan aplicada al recuento.

Select=COUNT frente a ItemCount (y por qué está obsoleto)

DescribeTable devuelve un ItemCount (y TableSizeBytes) gratis, sin costo de lectura. La trampa está en la propia referencia de la API: "DynamoDB actualiza este valor aproximadamente cada seis horas. Es posible que los cambios recientes no se reflejen en este valor". Así que puede quedarse muy por detrás del estado real de tu tabla.

Select=COUNTDescribeTable.ItemCount
ExactitudExacto (para el conjunto coincidente)Aproximado
FrescuraEn vivoActualizado ~cada 6 horas
CostoLee + factura cada elemento contadoGratis (metadatos)
Puede filtrar / contar un subconjuntoSí (expresión de filtro)No — solo toda la tabla

Usa ItemCount para una comprobación rápida de "qué tan grande es esta tabla" o un mosaico de panel. Usa Select=COUNT cuando necesites un número exacto, filtrado o actual — y acepta el costo de lectura. Para algo verdaderamente en vivo y gratis, lleva un contador tú mismo (consulta Patrones de agregación abajo).

Por qué no hay SUM/AVG/MIN/MAX nativos

Las operaciones de lectura de DynamoDB devuelven elementos. No hay planificador de consultas que pliegue un conjunto de resultados en un escalar, así que no hay nada con lo que calcular un SUM o AVG. Contar es el único pliegue que ofrece la API, mediante 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 "una proyección formada a partir del comodín * o una lista de proyección de uno o más nombres de atributo o rutas de documento". No hay función de agregación ni cláusula GROUP BY en esa gramática — y ORDER BY toma una {{key}}, documentada como "una clave hash o una clave de ordenación para ordenar los resultados devueltos". Cada SELECT de PartiQL aún se compila en un GetItem, Query o Scan, así que SELECT SUM(total) FROM "Orders" simplemente no es expresable. (Más sobre el techo de PartiQL en PartiQL frente a SQL.)

Patrones de agregación (contadores, streams, del lado de la aplicación)

Como DynamoDB no agregará por ti, los patrones establecidos empujan el trabajo a otro lugar:

  • Elemento contador mantenido. Mantén un elemento dedicado (p. ej. PK = "STATS#orders") y haz ADD a un atributo numérico en cada escritura con un UpdateItem. Leer el agregado es entonces un solo GetItem — exacto y barato, pero tú eres dueño de la lógica de incremento, su coherencia y la contención si un contador recibe muchos golpes.
  • alimentando un agregador. Habilita un stream y conéctalo a una Lambda que actualice los totales acumulados (recuentos, sumas) a medida que cambian los elementos. Según los documentos de Streams de AWS, puedes configurar el StreamViewType del stream para que cada registro lleve las NEW_AND_OLD_IMAGES — "tanto la imagen nueva como la antigua del elemento" — suficiente para mantener actualizados los agregados de estilo SUM sin volver a escanear. Los registros del stream están sujetos a una vida útil de 24 horas ("los registros del stream dentro de un fragmento se eliminan automáticamente después de 24 horas"), así que el consumidor tiene que mantener el ritmo.
  • Pliegue del lado de la aplicación. Pagina a través de los elementos coincidentes y acumula el SUM/AVG/MIN/MAX en tu propio código. Correcto, pero lee (y factura) cada elemento cada vez — el mismo perfil de costo que Select=COUNT, más la transferencia de datos.
  • Descargar a análisis. Para agregación analítica pesada o ad hoc, exporta la tabla a S3 y consúltala con Athena, o transmítela a un almacén de datos. Según los documentos de exportación a S3 de AWS, exportar "no consume unidades de capacidad de lectura" y te permite "realizar análisis y consultas complejas usando servicios de AWS como Athena" — la ruta recomendada por AWS una vez que has superado la agregación por solicitud.

Cada uno intercambia simplicidad por o bien contabilidad en tiempo de escritura (contadores, streams) o costo en tiempo de lectura (escaneos del lado de la aplicación). Ningún patrón hace que DynamoDB mismo calcule un SUM gratis. La versión con agrupación de esta compensación — 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 hay y cuál es su total" — sin escribir un bucle de escaneo con paginación ni una Lambda, el SQL Workbench de DynoTable ejecuta agregados reales. Materializa tus tablas a través del runtime real de Query/Scan de DynamoDB, luego ejecuta un único SELECT encima — agregados, GROUP BY, HAVING, DISTINCT: 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 DESC

Eso es COUNT, SUM, AVG, MIN, MAX, GROUP BY y ORDER BY sobre un agregado calculado — nada de lo cual DynamoDB ni PartiQL pueden expresar (el ORDER BY de PartiQL se limita a atributos de clave) — en una sola sentencia. Esta es la misma cuña analítica que SQL para DynamoDB; para la historia completa de la agrupación consulta DynamoDB GROUP BY.

El Workbench es honesto sobre el modelo de acceso subyacente, no un pseudo-Postgres:

  • Las filas aún vienen a través del Query/Scan real de DynamoDB. Un GROUP BY sobre toda una tabla sigue siendo un Scan por debajo — el Workbench expone ese costo en lugar de ocultarlo, la misma compensación Query frente a Scan.
  • Los agregados se ejecutan sobre los atributos escalares materializados después de que las filas aterrizan.

FAQ

¿Puedo contar elementos en DynamoDB sin escanear? No exactamente. Para un recuento exacto y actual debes leer los elementos — Select=COUNT aún contabiliza cada elemento contado. Las únicas opciones sin escaneo son el aproximado DescribeTable.ItemCount (actualizado ~cada 6 horas) o un elemento contador que mantengas tú mismo en cada escritura.

¿Cómo cuento elementos por un GSI? Ejecuta Query (o Scan) contra el índice con Select=COUNT. Contar mediante una partición estrecha de GSI es mucho más barato que escanear la tabla base, porque solo lees los elementos de esa partición del índice — modela el índice en torno al recuento que necesitas.

¿Es preciso DescribeTable.ItemCount? Es aproximado. La referencia de la API indica que DynamoDB actualiza ItemCount y TableSizeBytes "aproximadamente cada seis horas", y "es posible que los cambios recientes no se reflejen en este valor". No lo uses donde importe un número exacto o en vivo.

¿Puede DynamoDB hacer SUM o AVG? No de forma nativa, y no en PartiQL — la gramática de SELECT de PartiQL no tiene funciones de agregación. Agrega en tu aplicación, mantén un contador (opcionalmente mediante 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 elementos evaluó DynamoDB antes de tu filtro; Count es cuántos quedan después. Son iguales cuando no hay expresión de filtro. Una gran brecha entre ellos significa un recuento ineficiente.


¿Necesitas sumar, promediar o agrupar tus datos de DynamoDB sin escribir un bucle de escaneo? Descarga DynoTable y ejecútalo en una pestaña del Workbench. ¿Comparando clientes primero? Mira dónde queda frente a una GUI de DynamoDB corriente.

Actualizado