Principiante7 min de lectura

Por qué un Scan de DynamoDB es lento y caro

Un Scan lee cada elemento de la tabla y solo filtra después. Es la operación a la que recurres por memoria muscular de SQL, y la que silenciosamente dispara tu factura mientras hace tu latencia peor que la del servidor RDS que dejaste atrás.

¿Por qué mi Scan de DynamoDB es lento y caro?

Un Scan lee todos los elementos de la tabla antes de que se ejecute la FilterExpression, por lo que pagas por leer toda la tabla sin importar cuántos resultados devuelva, y se vuelve más lento a medida que la tabla crece. El arreglo casi siempre es una Query indexada — modela el patrón de acceso alrededor de una clave para que DynamoDB toque una sola partición en lugar de todo.

  • Un Scan lee toda la tabla, cada vez. El tamaño, no tu número de resultados, decide lo que pagas y cuánto tarda.
  • La FilterExpression es una mentira sobre el coste. Se ejecuta después de que la lectura está medida, así que devolver 12 elementos puede facturar la lectura de 12 millones.
  • Un Scan se vuelve más lento a medida que creces. Una Query indexada se mantiene plana — toca una partición sin importar cuánto crezca la tabla.
  • El arreglo casi siempre es modelado, no ajuste. Si haces Scan para responder una pregunta rutinaria, te falta una clave.

Qué hace realmente un Scan

Viniendo de SQL, SELECT * FROM events WHERE type = 'checkout' parece gratis — el motor tiene un índice, o no lo tiene, pero de cualquier forma obtienes filas de vuelta. En DynamoDB no hay ningún planificador de consultas decidiéndolo por ti.

Un Scan recorre toda la tabla secuencialmente, 1 MB a la vez, y entrega cada página a tu FilterExpression. Lo que el filtro rechaza aún se lee, aún se mide y aún está en tu factura. (AWS: Scanning tables)

Esa es la trampa. El filtro parece una cláusula WHERE, pero cambia el conjunto de resultados, nunca el coste. Un Scan consume la misma capacidad de lectura haya o no un filtro presente. (AWS: Scanning tables)

Cuenta las unidades de lectura

DynamoDB mide las lecturas en unidades de capacidad de lectura (RCU). Una RCU compra una sola lectura fuertemente consistente de un elemento de hasta 4 KB; las lecturas eventualmente consistentes cuestan la mitad. Los elementos más grandes redondean hacia arriba al siguiente bloque de 4 KB. (AWS: Read/write capacity mode)

Toma una tabla de analítica, ProductEvents. Cada fila es un evento rastreado:

PK  = "TENANT#acme"
SK  = "TS#2026-06-23T14:08:55Z#evt_9f3a"
attrs: eventType, sessionId, userId, payloadBytes

Digamos que contiene 2.000.000 de eventos, cada uno de ~1 KB, todos bajo un inquilino muy activo. Quieres los checkouts de hoy. El movimiento reflejo:

Scan ProductEvents
FilterExpression: eventType = "checkout"

Ese filtro podría devolver 40 filas. Pero el Scan leyó los 2.000.000 de elementos primero. A ~1 KB cada uno (1 RCU por 4 KB, eventualmente consistente ≈ 0,5 RCU por 4 KB), mediste aproximadamente 250.000 RCU — y paginaste por ~500 MB de datos — para devolver 40 elementos.

Ahora modela el patrón de acceso como una clave y haz Query en su lugar:

Query ProductEvents
PK = "TENANT#acme"
AND SK begins_with "TS#2026-06-23"

Esto lee solo la porción coincidente de una partición. Si esas 40 filas de checkout más los demás eventos del día suman ~2 MB, pagas por ~2 MB de lecturas, no 500 MB. La misma respuesta, una fracción diminuta del coste — y la latencia se mantiene plana a medida que la tabla crece.

Scan vs Query, medidos

Scan + filtroQuery indexada
LeeCada elemento de la tablaUna partición, acotada por SK
Capacidad facturadaToda la tabla, antes del filtroSolo los elementos de tu porción
Nuestro ejemplo~250.000 RCU (~500 MB)unos pocos cientos de RCU (~2 MB)
LatenciaCrece con el tamaño de la tablaPlana a medida que la tabla crece
Número de resultadosNo decide nada sobre el costeCoincide con lo que pagas

La lección que codifica la tabla: en un Scan, tu número de resultados y tu factura no están relacionados. En una Query, van a la par.

Decide antes de hacer Scan

La mayoría de los Scan accidentales vienen de una pregunta: ¿puedo nombrar la partición que necesito? Si sí, es una Query. Si no, el arreglo es una clave, no un filtro más grande.

Aquí está la decisión en forma de flujo.

NoNoNecesito leer elementos¿Conozco la partition key?Query una partición¿Puede un GSI indexarlo?Añade un GSI, luego QueryScan último recurso

El camino casi siempre termina en Query; solo caes hasta Scan cuando ninguna clave — presente o añadible — encaja con el patrón de acceso.

Si el patrón es real y recurrente pero la tabla base no puede indexarlo, esa es la señal para añadir un índice secundario global para que la pregunta se convierta en una Query. Modelar tus claves en torno a tus patrones de acceso por adelantado es todo el juego — consulta diseño de tabla única.

Escribe la consulta indexada, no un filtro

Cuando sí necesitas una condición más allá de la clave, constrúyela deliberadamente en lugar de volcar todo en una FilterExpression. El Constructor de expresiones de DynamoDB genera por ti la KeyConditionExpression y los marcadores de atributo, para que la partition key y la sort key hagan la acotación — antes de que DynamoDB mida la lectura, no después.

KeyConditionExpression: PK = :tenant AND begins_with(SK, :day)

Cuándo un Scan está realmente bien

Un Scan no está prohibido — solo es el valor por defecto equivocado. Es la herramienta correcta cuando genuinamente quieres decir "leer todo":

  • Exportaciones puntuales o rellenos ejecutados a mano.
  • Tablas diminutas de configuración / búsqueda donde toda la tabla son unos pocos KB.
  • Trabajos en segundo plano que paginan toda la tabla a propósito. Divídelos entre workers con Segment / TotalSegments — un scan paralelo — en lugar de un largo rastreo secuencial. (AWS: Scanning tables)

Y ten en cuenta que PartiQL no te salva: SELECT * FROM ProductEvents WHERE eventType = 'checkout' sin un predicado de clave compila directamente a un Scan. Es el mismo tiro al pie con ropa de SQL. (Consulta Query vs Scan para el desglose completo.)

Cuando realmente necesitas analítica entre elementos — un GROUP BY, un JOIN, un agregado que DynamoDB no puede expresar — el Workbench SQL de DynoTable los ejecuta del lado del cliente sobre un conjunto de resultados acotado, en lugar de machacar la tabla con un Scan completo.

Próximos pasos

Estima lo que cuesta cualquiera de los dos patrones con la calculadora de capacidad, lee Query vs Scan para el contraste a nivel de API, y descarga DynoTable para ejecutarlos contra tus propias tablas y ver tú mismo la capacidad consumida.

Actualizado