LSI vs GSI en DynamoDB: Cuándo usar cada índice secundario
Diseñaste tu tabla DynamoDB con una clave primaria que funciona perfectamente para el patrón de acceso principal, y ahora el equipo de producto pide filtrar por un atributo completamente diferente. Antes de duplicar datos o rediseñar la tabla, entender la diferencia entre un Local Secondary Index (LSI) y un Global Secondary Index (GSI) en DynamoDB puede ahorrarte semanas de refactorización.
TL;DR: LSI vs GSI en DynamoDB
| Característica | LSI | GSI |
|---|---|---|
| Partition key | Misma que la tabla base | Cualquier atributo |
| Sort key | Atributo diferente al de la tabla | Cualquier atributo (opcional) |
| Creación | Solo en el momento de crear la tabla | En cualquier momento |
| Consistencia de lectura | Fuerte o eventual | Solo eventual |
| Límite de tamaño por partition key | 10 GB por valor de partition key | Sin límite adicional |
| Capacidad | Comparte con la tabla base | Capacidad independiente |
| Casos de uso típicos | Consultas alternativas dentro de la misma partición | Patrones de acceso completamente nuevos |
Cómo funcionan los índices secundarios en DynamoDB
DynamoDB almacena datos distribuidos en particiones físicas determinadas por la partition key. Cuando necesitas consultar por un atributo que no forma parte de la clave primaria, DynamoDB no puede enrutar la solicitud a una partición específica — tendría que hacer un full scan. Los índices secundarios resuelven esto manteniendo una proyección ordenada de los datos con una clave diferente.
La distinción fundamental: un LSI comparte la partition key de la tabla base y solo cambia la sort key. Un GSI puede usar cualquier atributo como partition key y sort key, creando efectivamente una vista completamente independiente de los datos.
- Tabla base: Los ítems se almacenan particionados por
UserIDy ordenados porOrderID. - LSI (OrderDate-index): Mantiene la misma partition key (
UserID) pero reordena los ítems dentro de cada partición porOrderDate. Solo puedes consultar órdenes de un usuario específico. - GSI (Status-OrderDate-index): Crea una distribución completamente nueva por
Status. Puedes consultar todas las órdenes con estado 'PENDING' sin conocer elUserID. - Proyección: Ambos índices almacenan una copia de los atributos proyectados. Esto tiene costo de almacenamiento y escritura.
Local Secondary Index (LSI): consultas alternativas dentro de la misma partición
Un LSI te permite ordenar y filtrar los ítems de una partición usando un atributo diferente a la sort key original. La restricción clave es que la partition key debe ser idéntica a la de la tabla base — no puedes cambiarla.
El límite de 10 GB por valor de partition key aplica al conjunto combinado de la tabla base más todos sus LSIs. Si una partición supera ese límite, las escrituras fallan con un error ItemCollectionSizeLimitExceededException. Este es el motivo principal por el que muchos equipos prefieren GSIs incluso cuando técnicamente un LSI sería suficiente.
La ventaja real del LSI es la consistencia de lectura fuerte. Si tu aplicación necesita leer datos recién escritos con garantía de consistencia inmediata, el LSI es la única opción entre los índices secundarios de DynamoDB.
Crear una tabla con LSI
Los LSIs deben definirse en el momento de crear la tabla. No se pueden añadir después.
aws dynamodb create-table \
--table-name Orders \
--attribute-definitions \
AttributeName=UserID,AttributeType=S \
AttributeName=OrderID,AttributeType=S \
AttributeName=OrderDate,AttributeType=S \
--key-schema \
AttributeName=UserID,KeyType=HASH \
AttributeName=OrderID,KeyType=RANGE \
--local-secondary-indexes \
'[{
"IndexName": "OrderDate-index",
"KeySchema": [
{"AttributeName": "UserID", "KeyType": "HASH"},
{"AttributeName": "OrderDate", "KeyType": "RANGE"}
],
"Projection": {"ProjectionType": "ALL"}
}]' \
--billing-mode PAY_PER_REQUEST \
--region us-east-1
Consultar usando el LSI
aws dynamodb query \
--table-name Orders \
--index-name OrderDate-index \
--key-condition-expression 'UserID = :uid AND OrderDate BETWEEN :start AND :end' \
--expression-attribute-values \
'{":uid": {"S": "user-42"}, ":start": {"S": "2024-01-01"}, ":end": {"S": "2024-03-31"}}' \
--region us-east-1
Nota el parámetro --consistent-read que puedes añadir aquí — no está disponible en GSIs.
Global Secondary Index (GSI): patrones de acceso completamente nuevos
Un GSI proyecta los datos con una partition key completamente diferente. DynamoDB mantiene esta proyección de forma asíncrona, lo que explica por qué las lecturas son siempre eventualmente consistentes — hay un lag de propagación entre la escritura en la tabla base y la actualización del índice.
En producción, ese lag normalmente es de milisegundos, pero no está garantizado. Si tu aplicación escribe un registro y luego inmediatamente lo consulta por el GSI, puede no encontrarlo. Este comportamiento sorprende a equipos que vienen de bases de datos relacionales.
(milisegundos, no garantizado) App->>GSI: Query (Status=PENDING) GSI-->>App: Puede no incluir el ítem recién escrito TB->>GSI: Replica el ítem App->>GSI: Query (Status=PENDING) GSI-->>App: Ítem visible
- Escritura en tabla base: El ítem se escribe en la partición correspondiente a
UserID. - Propagación asíncrona: DynamoDB replica el ítem al GSI de forma asíncrona. El tiempo de propagación no está garantizado.
- Lectura del GSI: Una consulta inmediata al GSI puede no ver el ítem recién escrito. Esto es consistencia eventual por diseño.
- Capacidad independiente: El GSI consume unidades de capacidad separadas de la tabla base cuando está en modo provisionado.
Añadir un GSI a una tabla existente
A diferencia del LSI, puedes añadir un GSI en cualquier momento. El parámetro --attribute-definitions solo debe incluir los atributos nuevos que son clave del GSI y que no están ya definidos en la tabla.
aws dynamodb update-table \
--table-name Orders \
--attribute-definitions \
AttributeName=Status,AttributeType=S \
AttributeName=OrderDate,AttributeType=S \
--global-secondary-index-updates \
'[{
"Create": {
"IndexName": "Status-OrderDate-index",
"KeySchema": [
{"AttributeName": "Status", "KeyType": "HASH"},
{"AttributeName": "OrderDate", "KeyType": "RANGE"}
],
"Projection": {"ProjectionType": "KEYS_ONLY"}
}
}]' \
--region us-east-1
Si OrderDate ya estaba definido como atributo de clave en la tabla (por ejemplo, como sort key del LSI creado anteriormente), DynamoDB rechazará el comando con un error de atributo duplicado. En ese caso, omite OrderDate de --attribute-definitions y deja solo Status.
Consultar usando el GSI
aws dynamodb query \
--table-name Orders \
--index-name Status-OrderDate-index \
--key-condition-expression 'Status = :s AND OrderDate >= :d' \
--expression-attribute-values \
'{":s": {"S": "PENDING"}, ":d": {"S": "2024-01-01"}}' \
--region us-east-1
El error de diagnóstico más común: confundir el lag del GSI con un bug de aplicación
El patrón que más veces hemos visto en producción: el equipo escribe un pedido, redirige al usuario a una página de 'mis pedidos' que consulta el GSI por UserID... y el pedido no aparece. El primer instinto es buscar un bug en el código de escritura.
El pedido sí se escribió. Está en la tabla base. El GSI simplemente no lo propagó todavía.
Para verificar si el problema es lag del GSI o una escritura fallida, consulta directamente la tabla base con la clave primaria:
aws dynamodb get-item \
--table-name Orders \
--key '{"UserID": {"S": "user-42"}, "OrderID": {"S": "order-99"}}' \
--region us-east-1
Si el ítem aparece aquí pero no en el GSI, es lag de propagación. Si no aparece aquí tampoco, hay un problema real de escritura. Este diagnóstico de dos pasos elimina horas de debugging innecesario.
La solución arquitectural es no leer del GSI inmediatamente después de escribir cuando necesitas consistencia. Usa GetItem o Query directamente en la tabla base para la lectura post-escritura, y reserva el GSI para consultas donde la consistencia eventual es aceptable.
Decidir entre LSI y GSI en DynamoDB
La regla práctica: si necesitas consultar datos de un usuario específico (o cualquier entidad con partition key conocida) con un criterio de ordenación diferente, considera el LSI — pero solo si puedes garantizar que ninguna partición crecerá más de 10 GB. En casi todos los demás casos, el GSI es la elección correcta por su flexibilidad y ausencia de límite de tamaño por partición.
Consideraciones de costo y capacidad
Cada GSI consume almacenamiento adicional proporcional a los atributos proyectados. Con ProjectionType: ALL, estás duplicando efectivamente el almacenamiento de la tabla. Con KEYS_ONLY o INCLUDE, reduces el costo pero puedes necesitar un fetch adicional a la tabla base si necesitas atributos no proyectados — lo que consume RCUs adicionales.
En modo provisionado, cada GSI requiere su propia configuración de RCU/WCU. Un GSI con capacidad insuficiente puede throttlear independientemente de la tabla base. En modo PAY_PER_REQUEST, la capacidad escala automáticamente en ambos.
Pricing and limits vary — always check the official AWS documentation for current values.
Verificar el estado de un GSI
Después de ejecutar update-table para añadir un GSI, la tabla entra en estado UPDATING y el índice en estado CREATING. Durante este período, la tabla sigue siendo accesible para lecturas y escrituras, pero el índice no está disponible para consultas hasta que alcanza el estado ACTIVE.
aws dynamodb describe-table \
--table-name Orders \
--query 'Table.GlobalSecondaryIndexes[*].{Index:IndexName,Status:IndexStatus}' \
--region us-east-1
Próximos pasos con LSI y GSI en DynamoDB
Si estás diseñando una tabla nueva, define todos los patrones de acceso antes de crear la tabla — los LSIs no se pueden añadir después. Si ya tienes una tabla en producción y necesitas un nuevo patrón de consulta, el GSI es tu única opción sin rediseñar la tabla.
Para profundizar en el diseño de acceso en DynamoDB, la documentación oficial de índices secundarios y la guía de mejores prácticas para índices son los recursos de referencia.
Glosario
| Término | Definición |
|---|---|
| Partition Key | Atributo que DynamoDB usa para determinar en qué partición física se almacena un ítem. Debe ser único en combinación con la sort key. |
| Sort Key | Atributo secundario de la clave primaria que permite ordenar y filtrar ítems dentro de una misma partición. |
| LSI (Local Secondary Index) | Índice que comparte la partition key de la tabla base pero usa una sort key diferente. Solo se puede crear junto con la tabla. |
| GSI (Global Secondary Index) | Índice con partition key y sort key independientes de la tabla base. Se puede añadir en cualquier momento. |
| Consistencia eventual | Modelo de lectura donde los datos pueden no reflejar las escrituras más recientes de forma inmediata, pero convergen con el tiempo. |
Comentarios
Publicar un comentario