Intermedio6 min de lectura

Claves de ordenación compuestas en DynamoDB

Una clave primaria compuesta es una clave de partición más una clave de ordenación. El truco que la hace poderosa es lo que pones dentro de la clave de ordenación: codifica una jerarquía como una sola cadena delimitada, y un único Query lee un subárbol entero en orden de ordenación — sin joins, sin recursión, sin un segundo viaje de ida y vuelta.

¿Cómo funcionan las claves de ordenación compuestas en DynamoDB?

Una clave de ordenación compuesta empaqueta una jerarquía en una sola cadena delimitada — root/photos/2026/ — que DynamoDB almacena en orden de bytes UTF-8. Como la disposición ya coincide con el árbol, un único Query con begins_with(SK, "root/photos/") lee un subárbol entero en orden de ruta. Sin joins, sin recursión, sin un segundo viaje de ida y vuelta — solo un scan de prefijo sobre una porción contigua.

  • La clave de ordenación es una cadena ordenable, no solo un ID. Empaqueta una ruta dentro — root/photos/2026/ — y DynamoDB almacena los items de la partición en orden de bytes UTF-8 automáticamente.
  • Un delimitador convierte las coincidencias de prefijo en lecturas de subárbol. begins_with(SK, "root/photos/") devuelve todos los descendientes de esa carpeta en una sola consulta.
  • Las claves de ordenación admiten condiciones de rango, no filtros arbitrarios. Tienes begins_with, between, >, < — diseña la clave para que la lectura que necesitas sea un prefijo o un rango, no un Scan.
  • El delimitador es crítico. Elige uno que no pueda aparecer en un segmento de ruta, o dos ramas no relacionadas colisionarán.

Por qué la clave de ordenación lo es todo

Si vienes de SQL, modelarías un árbol de carpetas con un self-join parent_id y lo recorrerías recursivamente — una consulta por nivel. En DynamoDB eso es un error de diseño N+1 contra un almacén clave-valor que no tiene joins.

DynamoDB almacena cada item bajo una clave de partición ordenado por su clave de ordenación, en orden de bytes UTF-8 para cadenas (AWS: Query key conditions). Así que si tu clave de ordenación es la ruta, la disposición física ya coincide con el árbol. Una lectura se convierte en un scan de prefijo sobre una porción contigua — no en un recorrido de grafo.

Ese es el cambio: la clave de ordenación no es un identificador que coincides exactamente. Es una dirección ordenable. Diséñala y la consulta sale gratis.

Modela un árbol de sistema de archivos

Supón que almacenas árboles de archivos por cuenta. Un disco por cuenta es la partición natural; la ruta dentro de él es la clave de ordenación.

PKSKnode_typebytes
DRIVE#a91root/folder-
DRIVE#a91root/photos/folder-
DRIVE#a91root/photos/2026/folder-
DRIVE#a91root/photos/2026/beach.jpgfile284910
DRIVE#a91root/photos/2026/sunset.jpgfile512004
DRIVE#a91root/docs/folder-
DRIVE#a91root/docs/taxes.pdffile88210

Dos convenciones originales hacen el trabajo aquí:

  • PK = DRIVE#<account> mantiene todo el árbol de una cuenta en una sola item collection, así que cualquier lectura de subárbol es un Query de una sola partición.
  • SK es la ruta completa con una / final en las carpetas. La barra final es deliberada — hace que una carpeta se ordene antes que sus propios hijos y mantiene root/photos/ distinto de un archivo hermano llamado root/photos.

Lee un subárbol en una consulta

Lista todo lo que hay bajo root/photos/ — carpeta, subcarpetas y archivos, recursivamente:

Query
KeyConditionExpression = PK = :drive AND begins_with(SK, :prefix)
:drive   = "DRIVE#a91"
:prefix  = "root/photos/"

Eso devuelve root/photos/, root/photos/2026/, beach.jpg y sunset.jpg — en orden de ruta, en una sola lectura facturada. Pagas solo por los items de esa porción, no por todo el disco.

En DynoTable, ejecutas exactamente esta consulta begins_with contra la clave de ordenación de ruta y la carpeta junto con sus descendientes vuelven en orden de ruta — sin sintaxis de placeholders que escribir a mano.

¿Necesitas el KeyConditionExpression en bruto (nombres, valores y begins_with) para tu propio código? Constrúyelo y cópialo en el DynamoDB Expression Builder.

Ejecutando una consulta begins_with sobre la clave de ordenación de ruta en DynoTable, devolviendo una carpeta y sus descendientes en orden de ruta.
Ejecutando una consulta begins_with sobre la clave de ordenación de ruta en DynoTable, devolviendo una carpeta y sus descendientes en orden de ruta.

Lista un nivel, no todo el subárbol

begins_with te da la lectura recursiva. Para un listado de directorio no recursivo — los hijos inmediatos de root/photos/ y nada más profundo — almacena un atributo de profundidad y añade un rango de clave de ordenación más un filtro, o divide la ruta en un GSI parent. La versión más simple: mantén un atributo parent (root/photos/) y un GSI con clave sobre él.

La idea: una clave de ordenación responde preguntas de prefijo y rango de forma barata. "Solo hijos directos" es una pregunta diferente — modélala explícitamente en lugar de esperar que un FilterExpression la haga eficiente. Un filtro se ejecuta después de la lectura y pagas por cada item que descarta.

Elige el delimitador con cuidado

El delimitador forma parte de tu contrato de datos. Dos reglas:

  • Nunca debe aparecer dentro de un segmento de ruta. Si los nombres de archivo pueden contener /, / es el delimitador equivocado — un archivo llamado a/b es indistinguible de una carpeta a que contiene b. Elige un byte reservado (algunos equipos usan # o un carácter de control) y prohíbelo en los segmentos.
  • Cuidado con el orden de ordenación en los límites. / (0x2F) se ordena antes que los dígitos y las letras, que suele ser lo que quieres para el orden del árbol. Cambia el delimitador y cambias la ordenación — verifícalo contra datos reales.

Clave de ordenación compuesta vs. un atributo de ordenación separado

Clave de ordenación compuesta (root/photos/2026/x)ID de ordenación simple + atributo parent
Lectura de subárbolUna consulta begins_withConsultas recursivas (N+1) o un recorrido de GSI
OrdenaciónOrden de ruta, gratisHay que añadir un atributo de ordenación explícito
Mover / renombrarReescribir todos los descendientesActualizar un puntero parent
Listado de hijos directosNecesita atributo de profundidad o GSINatural (parent = x)

Las claves compuestas ganan cuando las lecturas tienen forma de subárbol y la ordenación importa; el modelo de ID plano gana cuando el árbol muta constantemente. La mayoría de las jerarquías intensivas en lecturas — árboles de archivos, árboles de categorías, organigramas — se inclinan hacia las compuestas.

Trampas y próximos pasos

  • No sobrecargues la clave. Todo lo que codificas es inmutable e indexado solo por prefijo. Los atributos por los que consultas por igualdad pertenecen a sus propios campos o a un GSI, no embutidos en la clave de ordenación.
  • Una clave de ordenación no puede hacer un WHERE arbitrario. Solo begins_with, between y comparaciones. Si te encuentras recurriendo a un FilterExpression, probablemente has modelado mal la clave — ver Query vs. Scan.
  • Profundizar en el diseño de claves vive en single-table design; para cuando una lectura de subárbol necesita un índice en lugar de la tabla base, ver GSI vs. LSI.

Construye la condición de clave begins_with con el Expression Builder, luego descarga DynoTable para ejecutar estas consultas de prefijo contra tus propias tablas y ver volver un subárbol en orden de ruta.

Actualizado