Intermédiaire9 min de lecture

Trier DynamoDB sur un attribut changeant

Tu modélises une clé de tri autour d'un attribut pour pouvoir interroger les items dans son ordre — puis l'attribut change. Le statut d'un ticket, l'état d'une commande, la priorité d'une tâche. Voici le piège que te tend DynamoDB : tu ne peux pas mettre à jour un attribut de clé sur place. Une clé primaire est immuable pour toute la vie de l'item. Change une valeur qui fait partie de la clé et tu n'es pas en train d'éditer un item — tu le déplaces, ce que DynamoDB t'oblige à faire explicitement.

Peux-tu modifier une clé de tri DynamoDB ?

Non. Une clé de tri fait partie de la clé primaire, et les attributs de clé DynamoDB sont immuables — UpdateItem ne peut pas modifier la valeur d'une clé de partition ou de tri, et il n'existe pas d'opération « déplacer l'item ». Pour la changer, supprime l'ancien item et fais un put d'un nouveau, ou garde plutôt la valeur volatile sur une clé de tri de GSI.

  • Les attributs de clé sont immuables. Tu ne peux pas faire d'UpdateItem sur une valeur de clé de partition ou de tri — DynamoDB n'a pas d'opération « déplacer l'item ».
  • Pour changer une valeur de clé, tu supprimes l'ancien item et tu fais un put d'un nouveau — idéalement dans une transaction pour que ce soit atomique.
  • Mieux : garde la valeur volatile hors de la clé de la table de base et mets-la sur une clé de tri de GSI — les clés de GSI peuvent changer, car mettre à jour l'item de base ne fait que re-propager l'entrée d'index.
  • Choisis des clés de tri qui ne changent pas (horodatages, ids immuables) chaque fois que le mode d'accès le permet.

Le problème : un statut sur lequel tu veux trier, mais qui n'arrête pas de changer

Disons que tu gères un service d'assistance et que tu veux lister les tickets d'une équipe triés par statut, alors tu mets le statut dans la clé de tri :

PK: TEAM#7   SK: STATUS#open#TICKET#8842

Maintenant le ticket passe à pending. Tu aimerais simplement faire un UpdateItem de la clé de tri vers STATUS#pending#TICKET#8842 — mais DynamoDB rejette toute écriture qui change un attribut de clé. La clé est l'adresse de l'item ; tu ne peux pas éditer l'adresse sur place. Le statut que tu as choisi pour trier est précisément la chose qui ne tient pas en place.

Option 1 : supprimer et recréer (de façon atomique)

Si la valeur doit vivre dans la clé de la table de base, la changer signifie retirer l'ancien item et écrire le nouveau :

1. DeleteItem  PK=TEAM#7  SK=STATUS#open#TICKET#8842
2. PutItem     PK=TEAM#7  SK=STATUS#pending#TICKET#8842  (same attributes)

Fais-le à l'intérieur d'un TransactWriteItems pour que la suppression et le put réussissent tous les deux ou échouent tous les deux — sinon un crash entre les deux perd le ticket ou le duplique. Ça marche, mais chaque changement de statut représente désormais deux écritures plus une transaction ; correct pour des changements occasionnels, coûteux pour ceux qui sont fréquents.

Option 2 : garder la valeur mutable hors de la clé de base (préférable)

La conception la plus propre : fais de la clé de la table de base quelque chose d'immuable (l'id du ticket) et mets la valeur volatile et triable sur une clé de tri de GSI.

Base:  PK: TICKET#8842   status: "open"   teamId: TEAM#7
GSI:   GSI1PK: TEAM#7    GSI1SK: STATUS#open#TICKET#8842

Maintenant, changer le statut est un simple UpdateItem sur l'attribut status de l'item de base — ce que DynamoDB autorise, car status n'est pas une clé de la table de base. DynamoDB re-propage alors l'entrée du GSI automatiquement vers sa nouvelle position triée. Un seul appel API, avec l'atomicité gérée pour toi — pas de transaction, pas de danse de suppression (sous le capot, DynamoDB supprime quand même l'ancienne entrée d'index et écrit la nouvelle, donc un changement indexé coûte environ 3 unités d'écriture contre environ 4 pour une suppression-et-put transactionnelle).

OuiNon, c'est une clé de tri de GSILe statut passe de open àpendingValeur dans une clé de la table debase ?Supprimer + recréer dans unetransactionSimple UpdateItem ; le GSIre-propage

Le compromis : le GSI est en cohérence à terme et coûte du stockage/des écritures supplémentaires — mais pour une valeur qui change souvent, c'est un peu moins cher (environ 3 contre 4 unités d'écriture) et bien plus simple que supprimer-et-recréer à chaque changement.

Concevoir les clés dans DynoTable

Construis et prévisualise les conditions de clé pour la lecture de base et la lecture du GSI dans le générateur d'expressions DynamoDB.

Dans DynoTable, tu choisis ensuite par quel index une requête passe et tu regardes la valeur volatile se trier sur le GSI pendant que l'item de base conserve sa clé immuable — les deux lectures côte à côte sur des données réelles.

Interroger un GSI trié par statut pendant que l'item de base conserve une clé immuable dans DynoTable.
Interroger un GSI trié par statut pendant que l'item de base conserve une clé immuable dans DynoTable.

Pièges + étapes suivantes

  • N'essaie jamais de faire un UpdateItem sur un attribut de clé — c'est rejeté ; les valeurs de clé sont fixées pour toute la vie de l'item.
  • Si tu dois la déplacer, fais delete+put dans une transaction — jamais sous forme de deux écritures non protégées.
  • Préfère des clés de base immuables + un GSI pour tout attribut sur lequel tu tries et que tu mutes.
  • N'oublie pas la cohérence à terme du GSI — l'entrée re-triée apparaît après un bref délai de propagation.
  • Voir aussi : stratégies de clé de tri, GSI vs LSI, transactions.

Tu veux voir comment un attribut mutable se trie sur un GSI par rapport à la table de base ? Télécharge DynoTable et explore tes index directement.

Coût d'écriture : delete-and-put vs mise à jour GSI

Comparaison WCU approximative pour un item ticket de 1 Ko en us-east-1 on-demand (la facturation réelle suit les règles d'arrondi AWS) :

MotifAppels APIImpact WCU typique
Delete + put transactionnel sur la clé de baseTransactWriteItems (2 ops)~2× la taille d'item par op en tarification transaction
Update de l'attribut status ; le GSI se re-propageUn UpdateItemÉcriture de base + écriture GSI (~2 WCU pour un item 1 Ko + attributs projetés)

Le chemin GSI évite l'orchestration applicative et élimine la fenêtre où un crash entre delete et put perd la ligne. Tu échanges la cohérence à terme sur la lecture d'index contre des écritures plus simples.

Modélise la taille de ton item et le taux de mise à jour dans le calculateur de tarifs quand les changements de statut partent plusieurs fois par minute.

GSI sparse pour les listes triées par statut

Si seuls les tickets ouverts ont besoin d'une file triée par statut, utilise un index sparse : écris GSI1PK = TEAM#7 et GSI1SK = STATUS#open#... seulement tant que status = open. Quand le ticket se ferme, retire ou omets les attributs de clé GSI à l'update — l'item sort de l'index sans delete-and-put sur la clé de tri de base.

Ça garde l'index petit et évite d'indexer des tickets fermés que tu ne listes jamais.

Clés de base immuables à préférer

Champ volatilSK table de baseMeilleure SK de baseLe champ volatil vit sur
Statut de commandeSTATUS#shipped#ORD#99ORD#99Tri GSI ou attribut
Priorité de tâcheP#1#TASK#12TASK#12Tri GSI
Nom d'affichage utilisateurNAME#alice#USER#5USER#5Attribut hors clé

Les timestamps et ids immuables (CREATED#2026-06-27T10:00:00Z, TICKET#8842) font de stables clés de tri de base quand tu as besoin d'ordre chronologique sur la table de base elle-même.

Concevoir le GSI avant de coder

Cartographie les modes d'accès dans l' outil de single-table design — entre « lister les tickets ouverts par équipe, ordre de priorité » et inspecte les templates GSI1PK / GSI1SK suggérés. Puis construis la condition de clé dans l' expression builder et émets une requête paginée avec le query builder pour les tests d'intégration.

Read-your-writes après un changement de statut

Après UpdateItem, une lecture fortement cohérente sur la table de base montre le nouveau status immédiatement. Une requête sur le GSI peut laguer brièvement. Les flux UI qui redirigent vers une file triée par GSI doivent tolérer des lignes périmées ou re-fetcher depuis la table de base par id quand la précision compte.

Mis à jour