Intermedio8 min de lectura

Proyecciones de índice en DynamoDB

Cuando creas un índice secundario, DynamoDB no copia automáticamente el item entero en él. Eliges qué se copia — la proyección del índice. Elige demasiado poco y tus queries pagan una segunda lectura para traer el resto; elige todo y pagas extra de almacenamiento y coste de escritura en cada update. Es un tradeoff que fijas una vez al crear el índice y con el que vives.

(No lo confundas con una expresión de proyección, que recorta los atributos que una sola lectura devuelve. Esta página va de lo que un índice almacena físicamente — mira expresiones de proyección para la otra.)

¿Qué es una proyección de índice en DynamoDB?

Una proyección es el conjunto de atributos que DynamoDB copia de la tabla base a un índice secundario. Eliges uno de tres tipos: KEYS_ONLY (solo las claves), INCLUDE (claves más una lista nombrada de atributos), o ALL (el item entero). Más proyección significa menos fetches a la tabla base pero más almacenamiento y coste de escritura.

  • Una proyección es el conjunto de atributos copiados a un índice secundario.
  • KEYS_ONLY — solo las claves de tabla e índice. Lo más pequeño y barato.
  • INCLUDE — las claves más una lista nombrada de atributos extra que eliges.
  • ALL — cada atributo del item. Lo más grande; las queries nunca necesitan la tabla base.
  • Un atributo que no está proyectado simplemente no está disponible desde un GSI — tu app debe emitir sus propias lecturas a la tabla base. (Solo un LSI te trae atributos no proyectados, a coste de lectura extra.)
  • Más proyección = más almacenamiento + más coste de escritura, porque cada escritura de la tabla base se propaga al índice.

El problema: el índice que te hace leer dos veces

Digamos que llevas un support desk con un GSI que te deja listar tickets open por prioridad. Proyectas KEYS_ONLY para mantenerlo magro. La query vuelve rápido — pero solo te da IDs de ticket, y tu pantalla de cola necesita el subject, assignee y age de cada ticket.

Así que ahora tu código hace una segunda ronda de lecturas contra la tabla base para hidratar cada resultado. La "una query" que diseñaste es en realidad una query más N gets, y la latencia y el coste que intentabas ahorrar vuelven enteros. La proyección era demasiado fina para el patrón de acceso.

Qué copia cada tipo de proyección

Item base: claves + subject +assignee + age + bodyKEYS_ONLY: solo clavesINCLUDE: claves + subject,assignee, ageALL: cada atributo
  • KEYS_ONLY guarda solo la clave de la tabla base y la clave del índice. Úsalo cuando la query solo necesita saber qué items coinciden y traerás detalles en otro sitio — o no en absoluto.
  • INCLUDE guarda las claves más una lista fija de atributos que nombras. El punto dulce: proyecta exactamente los campos que tu query necesita para renderizar, y nada más.
  • ALL copia el item entero. Las queries se sirven por completo desde el índice, a costa de duplicar todo el almacenamiento y el throughput de escritura del item en él.

Para la cola del support desk, INCLUDE con subject, assignee y age es la llamada correcta — la cola se renderiza desde el índice solo, sin segundo fetch y sin duplicar el body grande del ticket en el índice.

El coste que estás intercambiando

Cada atributo que proyectas se almacena una segunda vez y se reescribe en el índice cada vez que el item base cambia. Así que una proyección ALL generosa en una tabla que se actualiza a menudo multiplica tanto el almacenamiento como la capacidad de escritura. Proyecta lo que la query lee, no "todo, por si acaso".

Un detalle que vale la pena saber: con un índice sparse, la proyección solo guarda los items que llevan la clave del índice — así que INCLUDE/ALL en un índice sparse se queda pequeño porque el propio índice es pequeño. Pesa el multiplicador de almacenamiento y escritura de tu proyección con la calculadora de pricing de DynamoDB, y monta las queries del índice con el generador de expresiones de DynamoDB.

Ver una proyección en DynoTable

DynoTable lista cada índice secundario de una tabla y te deja consultar directamente a través de uno. Ejecuta el mismo patrón de acceso contra la tabla base y contra un GSI y compara los resultados — los atributos que faltan en el resultado del índice son exactamente los que no proyecta, así que el efecto de una proyección se ve sin releer la definición de la tabla.

Eligiendo por qué índice de DynamoDB corre una query, en el selector de índice de DynoTable.
Eligiendo por qué índice de DynamoDB corre una query, en el selector de índice de DynoTable.

Escollos + próximos pasos

  • Un atributo no proyectado en un GSI significa un fetch a la tabla base — diseña la proyección alrededor de lo que la query renderiza.
  • ALL rara vez es gratis — duplica almacenamiento y coste de escritura; por defecto usa INCLUDE salvo que el índice necesite de verdad cada campo.
  • Las proyecciones son en su mayoría fijas. No puedes editar libremente la proyección de un GSI después sin recrear el índice — elige a propósito desde el principio.
  • Relacionado: GSI vs LSI e índices sparse moldean cuánto almacena realmente una proyección.

¿Quieres ver qué devuelve cada uno de tus índices antes de rediseñarlos? Descarga DynoTable y consulta tus tablas directamente.

Coste de hidratación: KEYS_ONLY + N gets

Volvamos al ejemplo de la cola del support desk: 50 tickets open mostrados con subject, assignee y age.

ProyecciónQuery al índiceLecturas de seguimientoBoceto de RCU EC (items base 2 KB)
KEYS_ONLY50 claves devueltas50 × GetItem~50 RCU índice + ~50 RCU base
INCLUDE subject, assignee, age50 filas autocontenidasninguna~50 RCU índice solo
ALL50 copias completasninguna~50 RCU índice; más storage + write amp

Los números exactos dependen de los tamaños de los atributos proyectados — pega un ticket de muestra en la calculadora de tamaño de item y multiplica por la profundidad de la cola. Un INCLUDE que lista solo campos de UI a menudo gana a ALL cuando el atributo body es grande y rara vez se muestra en la vista de lista.

Comportamiento de fetch de proyección en LSI

Solo los LSI pueden opcionalmente traer atributos no proyectados de la tabla base durante una query (con coste de lectura adicional). Los GSI nunca hacen esto — los atributos ausentes requieren que tu aplicación llame a GetItem en la tabla base. Esa diferencia empuja muchos diseños de GSI hacia proyecciones INCLUDE un poco más anchas desde el principio.

Cambiar proyecciones después

Las proyecciones de GSI se fijan en el momento de creación. Ampliar KEYS_ONLY a INCLUDE requiere crear un índice nuevo, backfill, cortar el tráfico y borrar el índice viejo — planifica los campos antes del launch. Los LSI comparten la misma limitación.

Al evaluar un nuevo patrón de acceso, consulta el índice candidato en DynoTable y lista qué atributos aparecen — los huecos mapean 1:1 a entradas de proyección que faltan.

Combínalo con índices sparse

Un GSI sparse que indexa solo tickets con status = open almacena proyecciones solo para filas open. Un INCLUDE en ese índice se queda barato incluso cuando la tabla base guarda millones de tickets cerrados — el índice nunca los copió.

Combínalo con patrones de índice sparse cuando el subconjunto filtrado es pequeño respecto a la tabla.

Construye primero el patrón de acceso

Usa el query builder para prototipar la query del GSI — condición de clave, expresión de proyección y filtro — antes de alterar CloudFormation. Cambia tipos de proyección en la discusión de diseño preguntando qué columnas renderiza la UI; todo lo demás se queda en la tabla base.

Actualizado