Intermédiaire6 min de lecture

Les clés de tri composites dans DynamoDB

Une clé primaire composite, c'est une clé de partition plus une clé de tri. L'astuce qui la rend puissante, c'est ce que tu mets dans la clé de tri : encode une hiérarchie sous forme d'une seule chaîne délimitée, et un seul Query lit un sous-arbre entier dans l'ordre de tri — pas de jointures, pas de récursion, pas de second aller-retour.

Comment fonctionnent les clés de tri composites dans DynamoDB ?

Une clé de tri composite encode une hiérarchie dans une seule chaîne délimitée — root/photos/2026/ — que DynamoDB stocke dans l'ordre des octets UTF-8. Comme la disposition correspond déjà à l'arbre, un seul Query avec begins_with(SK, "root/photos/") lit un sous-arbre entier dans l'ordre des chemins. Pas de jointures, pas de récursion, pas de second aller-retour — juste un scan de préfixe sur une tranche contiguë.

  • La clé de tri est une chaîne triable, pas juste un ID. Empile-y un chemin — root/photos/2026/ — et DynamoDB stocke automatiquement les items de la partition dans l'ordre des octets UTF-8.
  • Un délimiteur transforme les correspondances de préfixe en lectures de sous-arbre. begins_with(SK, "root/photos/") renvoie chaque descendant de ce dossier en une seule requête.
  • Les clés de tri supportent les conditions de plage, pas des filtres arbitraires. Tu as begins_with, between, >, < — conçois la clé pour que la lecture dont tu as besoin soit un préfixe ou une plage, pas un Scan.
  • Le délimiteur est porteur. Choisis-en un qui ne peut pas apparaître dans un segment de chemin, sinon deux branches sans rapport entrent en collision.

Pourquoi la clé de tri est tout le jeu

En venant de SQL, tu modéliserais une arborescence de dossiers avec un self-join parent_id et tu la parcourrais récursivement — une requête par niveau. Dans DynamoDB c'est un footgun N+1 contre un magasin clé-valeur qui n'a pas de jointures.

DynamoDB stocke chaque item sous une clé de partition trié par sa clé de tri, dans l'ordre des octets UTF-8 pour les chaînes (AWS : conditions de clé de Query). Donc si ta clé de tri est le chemin, la disposition physique correspond déjà à l'arbre. Une lecture devient un scan de préfixe sur une tranche contiguë — pas un parcours de graphe.

C'est ça le basculement : la clé de tri n'est pas un identifiant que tu compares à l'exact. C'est une adresse triable. Conçois-la et la requête en découle gratuitement.

Modéliser une arborescence de système de fichiers

Disons que tu stockes des arborescences de fichiers par compte. Un drive par compte est la partition naturelle ; le chemin à l'intérieur est la clé de tri.

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

Deux conventions originales font le travail ici :

  • PK = DRIVE#<account> garde toute l'arborescence d'un compte dans une seule collection d'items, donc toute lecture de sous-arbre est un Query mono-partition.
  • SK est le chemin complet avec un / final sur les dossiers. Le slash final est délibéré — il fait trier un dossier avant ses propres enfants et garde root/photos/ distinct d'un fichier voisin nommé root/photos.

Lire un sous-arbre en une requête

Liste tout ce qui se trouve sous root/photos/ — dossier, sous-dossiers et fichiers, récursivement :

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

Cela renvoie root/photos/, root/photos/2026/, beach.jpg et sunset.jpg — dans l'ordre des chemins, en une seule lecture facturée. Tu paies seulement pour les items de cette tranche, pas pour tout le drive.

Dans DynoTable, tu exécutes exactement cette requête begins_with sur la clé de tri de chemin et le dossier ainsi que ses descendants reviennent dans l'ordre des chemins — sans syntaxe de placeholders à écrire à la main.

Tu as besoin du KeyConditionExpression brut (noms, valeurs et begins_with) pour ton propre code ? Construis-le et copie-le dans le DynamoDB Expression Builder.

Exécution d'une requête begins_with sur la clé de tri de chemin dans DynoTable, renvoyant un dossier et ses descendants dans l'ordre des chemins.
Exécution d'une requête begins_with sur la clé de tri de chemin dans DynoTable, renvoyant un dossier et ses descendants dans l'ordre des chemins.

Lister un niveau, pas tout le sous-arbre

begins_with te donne la lecture récursive. Pour un listing de répertoire non récursif — les enfants immédiats de root/photos/ et rien de plus profond — stocke un attribut depth et ajoute une plage de clé de tri plus un filtre, ou découpe le chemin dans un GSI parent. La version la plus simple : garde un attribut parent (root/photos/) et un GSI clé dessus.

L'idée : une clé de tri répond aux questions de préfixe et de plage à bas coût. « Enfants directs uniquement » est une autre question — modélise-la explicitement plutôt que d'espérer qu'une FilterExpression la rende efficace. Un filtre s'exécute après la lecture et tu paies pour chaque item qu'il jette.

Choisis le délimiteur avec soin

Le délimiteur fait partie de ton contrat de données. Deux règles :

  • Il ne doit jamais apparaître dans un segment de chemin. Si les noms de fichiers peuvent contenir /, alors / est le mauvais délimiteur — un fichier nommé a/b est indiscernable d'un dossier a contenant b. Choisis un octet réservé (certaines équipes utilisent # ou un caractère de contrôle) et interdis-le dans les segments.
  • Attention à l'ordre de tri aux frontières. / (0x2F) trie avant les chiffres et les lettres, ce qui est généralement ce que tu veux pour l'ordre d'arbre. Change le délimiteur et tu changes l'ordre — vérifie-le sur de vraies données.

Clé de tri composite vs. attribut de tri séparé

Clé de tri composite (root/photos/2026/x)Clé de tri par ID + attribut parent
Lecture de sous-arbreUne requête begins_withRequêtes récursives (N+1) ou parcours de GSI
OrdreOrdre des chemins, gratuitDoit ajouter un attribut de tri explicite
Déplacement / renommageRéécrire tous les descendantsMettre à jour un seul pointeur parent
Listing d'enfants directsBesoin d'un attr depth ou d'un GSINaturel (parent = x)

Les clés composites gagnent quand les lectures sont en forme de sous-arbre et que l'ordre compte ; le modèle à ID plat gagne quand l'arbre mute constamment. La plupart des hiérarchies à lecture intensive — arborescences de fichiers, de catégories, organigrammes — penchent vers le composite.

Pièges et étapes suivantes

  • Ne sur-remplis pas la clé. Tout ce que tu encodes est immuable et indexé par préfixe seulement. Les attributs que tu requêtes par égalité ont leur place dans leurs propres champs ou un GSI, pas tassés dans la clé de tri.
  • Une clé de tri ne peut pas faire de WHERE arbitraire. Seulement begins_with, between et les comparaisons. Si tu te surprends à atteindre une FilterExpression, tu as probablement mal modélisé la clé — voir Query vs. Scan.
  • Pour aller plus loin sur la conception de clé, ça vit dans le single-table design ; et pour quand une lecture de sous-arbre a besoin d'un index plutôt que la table de base, voir GSI vs. LSI.

Construis la condition de clé begins_with avec l' Expression Builder, puis télécharge DynoTable pour exécuter ces requêtes de préfixe sur tes propres tables et observer un sous-arbre revenir dans l'ordre des chemins.

Mis à jour