Principiante6 min de lectura

Query vs Scan en DynamoDB

Query lee una única colección de Items por clave de partición (acotando opcionalmente por la clave de ordenación); Scan lee la tabla entera y filtra después. Se parecen en la API, pero facturan —y escalan— de forma completamente diferente.

¿Cuándo debo usar Query vs Scan en DynamoDB?

Usa Query siempre que puedas identificar la partición que necesitas — lee una única colección de Items y factura solo por los Items coincidentes. Recurre a Scan únicamente para exportaciones puntuales o tablas pequeñas; lee cada Item y factura la tabla entera antes de que se ejecute cualquier FilterExpression. Con datos reales, Query siempre gana.

  • Query es dirigido: pagas por los Items de la partición coincidente.
  • Scan es exhaustivo: pagas por leer cada Item y luego descartas la mayoría con un FilterExpression que se ejecuta después de medir la lectura.

En una tabla de cualquier tamaño real, un Scan con filtro es el clásico footgun del estilo «por qué mi factura es enorme y mi latencia es peor que la de RDS».

En paralelo

QueryScan
LecturasUna partición (por PK)Cada Item de la tabla
Capacidad facturadaItems coincidentes en la particiónTabla entera, antes de filtrar
FilterExpressionAplicado tras la lectura —aún se factura la lecturaIgual —filtrar nunca reduce el coste
LatenciaPlana a medida que crece la tablaCrece con el tamaño de la tabla
Paginación1 MB/página → LastEvaluatedKey1 MB/página; paralelizable
Úsalo paraPatrones de acceso conocidosExportaciones puntuales, tablas de config diminutas

La trampa clave: un FilterExpression se ejecuta después de que DynamoDB mide la lectura, en ambas operaciones. Un Scan que «devuelve 10 filas» puede facturar por leer un millón —filtrar es una comodidad, nunca un control de coste.

Lo que cuesta realmente un Scan completo

Ponle números. DynamoDB contabiliza las lecturas en unidades de 4 KB: una lectura cuesta una por cada 4 KB, y una lectura la mitad. Query y Scan suman el tamaño de cada Item que tocan —no de cada Item que devuelven— y redondean hacia arriba al siguiente múltiplo de 4 KB.

Toma una tabla de 1 millón de Items con una media de 2 KB por Item (~2 GB de datos) y un patrón de acceso que necesita 10 de esos Items:

Items leídosDatos contabilizadosUnidades de lectura (eventualmente consistente)
Scan + FilterExpression1,000,000~2 GB~262,000
Query sobre una clave coincidente1020 KB3

Los mismos 10 Items, a cinco órdenes de magnitud de distancia —y el Scan factura esas ~262,000 cada vez que se ejecuta, tanto si el filtro coincide con diez Items como si no coincide con ninguno. Con facturación son unidades de solicitud que van directas a la factura; en tablas , un Scan grande compite con el tráfico de producción por el rendimiento y puede throttlearlo hasta un ProvisionedThroughputExceededException.

Tres datos de coste más que sorprenden a la gente:

  • Select: COUNT no es gratis. Un Query o Scan de recuento consume exactamente la misma capacidad de lectura que leer los Items —simplemente no los devuelve.
  • Limit limita los Items evaluados, no los Items coincidentes. Combinado con un filtro, una página puede volver vacía y aun así facturar una página completa de lecturas.
  • Nunca tienes que adivinar. Pasa ReturnConsumedCapacity: TOTAL y cada respuesta informa de la capacidad que acaba de consumir.

Comprueba cuánto pesan tus propios Items con la calculadora de tamaño de Items y convierte después las unidades de lectura en una factura mensual con la calculadora de precios.

Usa Query

Query  PK = "USER#42"  AND  SK begins_with "ORDER#"

Si te ves recurriendo a Scan para responder a un patrón de acceso común, eso es una señal de modelado: añade un Global Secondary Index para que el patrón se convierta en un Query.

La elección se reduce a una pregunta: ¿puedes nombrar la partición que necesitas?

YesNoYesNoAccess patternPartition key known?Query reads one partitionCan a GSI key it?Add a GSIScan reads the whole table

Si conoces la clave, haces un Query; si no, añade un GSI para convertirlo en uno, y recurre a Scan solo cuando ninguna clave encaje.

Cuándo está bien usar Scan

Exportaciones puntuales, tablas de configuración diminutas y trabajos en segundo plano que paginan deliberadamente por toda la tabla. Usa Segment/TotalSegments para repartir un Scan entre workers (un —consulta scans paralelos en DynamoDB) cuando de verdad debas leerlo todo, y pagínalo correctamente con LastEvaluatedKey (guía de paginación). Si el problema es un Scan que ya ejecutas, por qué Scan es lento y caro te guía por el triaje.

Un SELECT * FROM table reflejo sobre DynamoDB es el mismo antipatrón con ropa de PartiQL —se compila a un Scan. Cuando de verdad necesitas analítica entre Items (un GROUP BY, un JOIN, un agregado), el SQL Workbench de DynoTable los ejecuta en el lado del cliente sobre un conjunto de resultados acotado en lugar de machacar la tabla.

Prueba DynoTable para ejecutar e inspeccionar estas consultas contra tus propias tablas —muestra la capacidad consumida de cada operación que ejecuta.

Actualizado