Les migrations DynamoDB sans interruption
En venant de SQL, une migration est un ALTER TABLE qui verrouille la table pendant
qu'il réécrit chaque ligne. DynamoDB n'a pas de schéma à altérer — les items sont
schemaless, donc ajouter un attribut ou un nouveau type d'entité est gratuit.
La partie difficile, c'est le mode d'accès que les nouvelles données doivent servir, et remodeler les données en direct pour le servir sans une réécriture stop-the-world.
Comment migrer une table DynamoDB sans interruption de service ?
DynamoDB n'a pas de ALTER TABLE, donc les migrations ne verrouillent jamais la table. Tu ajoutes des attributs, une nouvelle forme de clé ou un nouveau en ligne avec UpdateTable, puis tu remodèles les données en direct de façon incrémentale : backfille les anciens items paresseusement à la lecture ou avec un balayage limité en débit, et fais du dual-write des deux formats pendant la transition. Il n'y a pas de basculement flag-day.
- Il n'y a pas de
ALTER TABLE. Les items sont schemaless. Une « migration » signifie ajouter des attributs, une nouvelle forme de clé ou un nouvel index — jamais réécrire un ensemble de colonnes fixe. - Les nouvelles écritures sont faciles ; les anciens items sont le problème. Les lignes existantes ne portent pas les nouveaux attributs, donc tout nouvel index ou toute nouvelle requête les rate silencieusement jusqu'à ce que tu backfilles.
- Ajoute les index en ligne, backfille paresseusement.
UpdateTableconstruit un GSI sur une table en direct ; backfille les anciens items à la lecture (paresseux) ou avec un balayage contrôlé — jamais un basculement flag-day. - Dual-write pendant la transition. Tant que les deux formes coexistent, écris l'ancien et le nouveau format ensemble pour qu'aucun chemin de lecture ne devienne périmé.
Cadre-le comme un mode d'accès, pas une colonne
Disons que tu gères un produit d'espace de travail SaaS sur une seule table. Les items
utilisent PK = "WS#<id>" et un SK surchargé par entité :
| PK | SK | attributes |
|---|---|---|
| WS#a91 | META | name, tier |
| WS#a91 | DOC#2026-04-01#x7 | title, author, body |
| WS#a91 | DOC#2026-04-02#k2 | title, author, body |
Maintenant le produit veut des commentaires sur les documents, plus une nouvelle lecture : « lister chaque commentaire qu'un membre a écrit à travers l'espace de travail, le plus récent d'abord. » Cette dernière clause est la migration. Un nouveau type d'entité seul est trivial ; servir une requête que les clés actuelles ne peuvent pas répondre, c'est le travail.
Ajoute d'abord le nouveau type d'entité
Les commentaires ne sont que de nouveaux items dans la même partition — pas de cérémonie de migration, pas de nouvelle table :
| PK | SK | attributes |
|---|---|---|
| WS#a91 | DOC#2026-04-01#x7#CMT#01HZ... | author, text, createdAt |
Un Query sur PK = "WS#a91" avec SK begins_with "DOC#2026-04-01#x7#CMT#" liste déjà
les commentaires d'un document. Les documents existants sont intacts. Cette moitié livre
le jour un — voir les collections d'items et les clés surchargées
pour comprendre pourquoi la même partition contient les deux.
La nouvelle requête a besoin d'un GSI
« Tous les commentaires d'un membre, le plus récent d'abord » ne peut pas être servi par
la table de base — memberId n'est ni la PK ni un préfixe de SK. C'est un nouvel
index, et le choisir correctement est sa propre décision : voir
GSI vs LSI (un LSI doit exister à la création de la table, donc
pour une migration sur une table en direct un GSI est ta seule option).
Ajoute un GSI1 générique et écris les nouveaux attributs sur les nouveaux items de
commentaire :
| GSI1PK | GSI1SK |
|---|---|
| MEMBER#u44 | 2026-04-02T09:15:00Z |
Query GSI1 WHERE GSI1PK = "MEMBER#u44" avec ScanIndexForward = false donne les
commentaires les plus récents d'abord par membre.
Construis l'index en ligne
UpdateTable ajoute un GSI à une table en direct sans interruption. DynamoDB backfille
les items existants dans l'index en arrière-plan ; l'index reporte
CREATING/backfilling jusqu'à ce que ce soit fait, puis bascule vers ACTIVE
(Gérer les GSI).
Deux pièges ici. D'abord, AWS prévient qu'ajouter un GSI peut throttler les écritures
de la table de base si la nouvelle clé se distribue inégalement — ajoute-le dans une
fenêtre à faible trafic et surveille CloudWatch. Ensuite, l'index est à cohérence à
terme même après être passé ACTIVE ; une écriture peut ne pas être visible sur
le GSI pendant un instant. Voir
pourquoi les GSI sont à cohérence à terme.
Backfille les anciens items
Le GSI n'indexe que les items qui ont GSI1PK/GSI1SK. Tes commentaires
pré-migration — écrits avant que l'attribut existe — n'apparaissent jamais, même après
le backfill. Le backfill de GSI en ligne copie les items existants, mais il ne peut pas
inventer des attributs qui ne sont pas dessus. Tu dois ajouter les valeurs.
Deux stratégies :
| Stratégie | Comment ça marche | À utiliser quand |
|---|---|---|
| Paresseux | À la lecture d'un ancien item, réécris les nouveaux attributs | Les anciens items sont souvent lus ; étale le coût |
| Balayage | Un Scan paginé met à jour chaque ancien item une fois | Tu as besoin que le GSI soit complet pour une échéance |
Pour le balayage, pagine avec Scan, et pour chaque ancien commentaire ajoute les
attributs d'index avec un UpdateItem conditionnel pour ne jamais écraser une écriture
concurrente.
La condition garde sur l'attribut non déjà existant. Construis et copie la
ConditionExpression et l'UpdateExpression exactes avec le
DynamoDB Expression Builder plutôt que de taper à
la main attribute_not_exists(GSI1PK).
Dual-write pendant la transition
Tant que chaque ancien item ne porte pas les nouveaux attributs, deux formes coexistent. Le chemin d'écriture doit peupler le nouveau format à chaque écriture — nouveaux commentaires et toute mise à jour d'un ancien — pour que l'écart ne fasse que rétrécir.
Choisis une condition de fin de backfill que tu peux vérifier : le balayage a paginé toute la table, ou le chemin paresseux a tourné assez longtemps pour que les items non convertis soient périmés par conception. Seulement alors tu retires l'ancien chemin de lecture. Sauter ça, c'est comment une migration « se termine » pendant qu'une fraction des requêtes renvoie silencieusement des résultats tronqués.

Pièges
- Ajouter l'attribut ≠ backfillé. Un nouveau GSI démarre vide pour les anciens items. Vérifie la couverture avant de faire confiance à la requête.
- Changer une clé en place n'est pas une migration — c'est une réécriture. Tu ne
peux pas muter la
PK/SKd'un item ; tu écris un nouvel item sous la nouvelle clé et tu supprimes l'ancien. Planifie-le comme copier-puis-supprimer, avec dual-read entre les deux. - Pas de basculement transactionnel. Il n'y a aucun moment où toute la table bascule. Conçois chaque étape pour être sûre tant que les deux formes sont en direct.
Étapes suivantes
Vérifie la cohérence des nouvelles clés et des collections surchargées dans single-table design, et confirme que le backfill est complet en paginant la table en direct. Essaie DynoTable pour parcourir ta table, repérer les items non backfillés et exécuter les mises à jour conditionnelles sur tes propres données.


