Avanzado8 min de lectura

Cómo se almacena internamente un GSI de DynamoDB

Un Global Secondary Index no es un puntero de vuelta a tu tabla. Es una tabla separada y gestionada internamente — sus propias particiones, su propio esquema de claves, su propia capacidad — que DynamoDB mantiene sincronizada copiando las escrituras en ella de forma asíncrona.

Viniendo de SQL, un índice es un B-tree atornillado a la misma tabla física, actualizado dentro de la misma transacción. Un GSI rompe ambas suposiciones, y casi toda sorpresa con un GSI se remonta a ese único hecho.

¿Cómo se almacena un GSI de DynamoDB?

Un GSI de DynamoDB se almacena como una tabla separada y gestionada internamente — con sus propias particiones, su propio esquema de claves y su propia capacidad — no como un puntero hacia la tabla base. DynamoDB copia cada escritura en el índice de forma asíncrona, almacenando solo las claves del GSI, las claves de la tabla base y cualquier atributo proyectado.

  • Un GSI es su propia tabla. Tiene un espacio de particiones totalmente independiente con clave por la clave de partición del GSI, no la de la tabla base.
  • Las escrituras se replican de forma asíncrona. Tu escritura se confirma primero en la tabla base, luego DynamoDB la propaga a cada GSI por un camino de fondo.
  • Solo se almacenan los atributos proyectados. El índice guarda las claves del GSI, las claves base, más cualquier atributo que proyectaste — nada más.
  • La clave del GSI no tiene por qué ser única. Múltiples items base pueden compartir una clave de partición/ordenación del GSI; la clave primaria base es el desempate que los mantiene distintos.

Empieza con un item base

Toma un registro de auditoría SaaS. Cada acción privilegiada en un workspace se convierte en un evento inmutable. La tabla base, WorkspaceEvents, tiene clave de forma que todos los eventos de un workspace vivan en una colección de items, ordenados por tiempo:

WorkspaceEvents (base table)
EventPKEventSKactorIdverbtargetRef
WS#orbit-9TS#2026-06-23T14:02:11ZUSR#kpROLE_GRANTEDUSR#mara

EventPK = "WS#orbit-9" particiona por workspace; EventSK es un timestamp ISO de forma que una Query devuelve los eventos de un workspace en orden cronológico. Eso sirve perfectamente "muéstrame la línea de tiempo de este workspace".

No sirve nada más. No puedes preguntar "¿qué hizo USR#kp a través de cada workspace?" — actorId no es una clave, así que la única forma de responderla en la tabla base es un Scan completo. Ese es el patrón de acceso que un GSI existe para añadir.

Añade un GSI y observa aparecer una segunda tabla

Define un GSI, ByActor, que vuelve a particionar los mismos eventos por quién los realizó:

ByActor (GSI)
GSI1PK = actorId   ("USR#kp")
GSI1SK = EventSK   ("TS#2026-06-23T14:02:11Z")

DynamoDB ahora mantiene una segunda estructura física. El mismo evento lógico se almacena dos veces — una en la partición WS#orbit-9 de la tabla base, y otra en la partición USR#kp del GSI:

ByActor (GSI) — its own partition space
GSI1PKGSI1SKEventPKEventSKverb
USR#kpTS#2026-06-23T14:02:11ZWS#orbit-9TS#2026-06-23T14:02:11ZROLE_GRANTED

Fíjate en lo que viajó incluido: las claves de la tabla base (EventPK, EventSK) se almacenan automáticamente en cada item del GSI. Así es como un acierto en el GSI puede señalarte de vuelta al item completo — y por qué un índice KEYS_ONLY igual cuesta almacenamiento.

Qué vive realmente en el GSI

El índice no copia el item entero. Cada entrada del GSI guarda exactamente tres cosas, y solo controlas la tercera:

Almacenado en el GSIDe dónde viene¿Opcional?
Clave de partición + ordenación del GSILos atributos que nombraste como claves del GSINo
Clave(s) de la tabla baseCopiada de cada item baseNo
Atributos proyectadosTu elección de Projection

Projection es KEYS_ONLY, INCLUDE (una lista nombrada) o ALL. Una Query sobre el GSI solo puede devolver atributos que estén en el índice.

Pide uno que no esté proyectado y DynamoDB no lo obtiene de forma transparente — no recibes nada de vuelta para ese campo. (docs de GSI de AWS)

Esa es la trampa relacional al revés: SQL haría un join de vuelta al heap por la columna ausente. Un GSI nunca lo hace. La proyección es todo el contrato.

Cómo una escritura llega al índice

La replicación es la parte que más rompe la intuición SQL. Una escritura base y su actualización de índice no son una operación atómica.

Cuando haces PutItem, DynamoDB se confirma de forma durable en la tabla base, reconoce tu escritura y luego propaga el cambio a un camino de fondo que actualiza cada GSI. El reconocimiento no espera al índice.

Aquí está el orden de los eventos para nuestra escritura de auditoría, de arriba abajo:

PutItemevento WS#orbit-9Confirmar enpartición base200 OKal llamanteCamino async:extraer claves GSIEnrutar a ByActorpartición USR#kpEscribir atributosproyectados

El llamante recibe su 200 OK en el paso tres, antes de que terminen los pasos cuatro a seis — así que una Query sobre ByActor en ese hueco puede perderse un evento recién creado.

Esa asincronía es por diseño, no un defecto: es el linaje del paper de Amazon Dynamo de 2007, que eligió disponibilidad sobre consistencia síncrona. Las consecuencias completas viven en por qué un GSI es eventualmente consistente.

La clave del GSI no es una clave única

En SQL, un índice secundario no único es el default y uno único es una restricción a la que optas. Un GSI es lo opuesto: no tiene garantía de unicidad, nunca.

Dos eventos de auditoría del mismo actor con timestamps que colisionan compartirían la misma GSI1PK y GSI1SK. DynamoDB almacena ambos — los desambigua internamente por la clave primaria de la tabla base, que siempre va incluida.

Así que una Query del GSI para un actor en un instante puede legítimamente devolver varios items. Si asumiste una-fila-por-clave como te daría un índice único de SQL, ese es el footgun.

Cuando consultas el índice, el constructor de expresiones de DynamoDB escribe la KeyConditionExpression con nombres y valores escapados correctamente — p. ej. emparejar un actor desde un corte:

KeyConditionExpression: "#a = :actor AND #ts > :since"
ExpressionAttributeNames:  { "#a": "actorId", "#ts": "EventSK" }
ExpressionAttributeValues: {
  ":actor": { "S": "USR#kp" },
  ":since": { "S": "TS#2026-06-01T00:00:00Z" }
}

La capacidad vive con el índice, no con la tabla

Como el GSI es su propia tabla, tiene su propia capacidad de lectura y escritura, facturada y throttleada por separado de la tabla base. Una lectura de ByActor consume las unidades de lectura del GSI, nunca las de la tabla.

El acoplamiento inverso es el que muerde: cada escritura de la tabla base también escribe el índice, y si el GSI no puede absorber eso, ejerce contrapresión sobre la escritura base. Ese mecanismo tiene su propia guía — cuándo un GSI throttlea las escrituras de la tabla base.

Por esto también la clave de partición de un GSI importa tanto como la de la tabla base. Una clave de GSI de baja cardinalidad agrupa las escrituras en una partición del índice aunque las escrituras base estén perfectamente repartidas — una partición caliente que creaste al re-clavar.

Trampas y próximos pasos

  • No esperes recuperar atributos no proyectados. Una Query del GSI devuelve solo lo que el índice almacena. Si necesitas el item completo, proyéctalo u obténlo de la tabla base por las claves incluidas.
  • No trates una clave del GSI como única. Planifica que una Query devuelva más de un item por clave; la clave primaria base es la única identidad real.
  • No leas un GSI justo después de la escritura que lo alimentó. El camino async significa que el índice puede no mostrar tu escritura aún — lee la tabla base cuando necesites leer tus propias escrituras.
  • Dimensiona la capacidad del GSI deliberadamente. Es independiente en lecturas y una dependencia oculta en escrituras.

Todo el juego es elegir formas de clave que sirvan a tus patrones — diseño de tabla única sobrecarga un GSI a través de muchos de ellos; GSI vs LSI cubre cuándo encaja un índice local en su lugar.

Construye y previsualiza tu KeyConditionExpression del GSI en el constructor de expresiones de DynamoDB, luego prueba DynoTable para inspeccionar los atributos proyectados de un índice y observar las escrituras replicarse en el GSI sobre tus propias tablas.

Actualizado