Migrazioni DynamoDB Senza Downtime
Venendo da SQL, una migrazione è un ALTER TABLE che blocca la tabella mentre
riscrive ogni riga. DynamoDB non ha schema da alterare — gli Item sono schemaless, quindi
aggiungere un attributo o un nuovo tipo di entità è gratis.
La parte difficile è il pattern di accesso che i nuovi dati devono servire, e rimodellare i dati live per servirlo senza una riscrittura stop-the-world.
Come si esegue una migrazione di una tabella DynamoDB senza downtime?
DynamoDB non ha ALTER TABLE, quindi le migrazioni non bloccano mai la tabella. Aggiungi attributi, una nuova forma di chiave o un nuovo online con UpdateTable, poi rimodella i dati live in modo incrementale: fai il backfill dei vecchi Item in lettura (lazy) o con uno sweep controllato, e usa il dual-write di entrambi i formati durante la transizione. Non esiste un cutover flag-day.
- Non c'è
ALTER TABLE. Gli Item sono schemaless. Una "migrazione" significa aggiungere attributi, una nuova forma di chiave o un nuovo indice — mai riscrivere un insieme fisso di colonne. - Le nuove scritture sono facili; i vecchi Item sono il problema. Le righe esistenti non portano i nuovi attributi, quindi ogni nuovo indice o query li manca silenziosamente finché non fai il backfill.
- Aggiungi indici online, fai il backfill lazy.
UpdateTablecostruisce un GSI su una tabella live; fai il backfill dei vecchi Item in lettura (lazy) o con uno sweep controllato — mai un cutover flag-day. - Dual-write durante la transizione. Mentre entrambe le forme coesistono, scrivi il vecchio e il nuovo formato insieme così nessun percorso di lettura diventa obsoleto.
Inquadralo come pattern di accesso, non come colonna
Diciamo che gestisci un prodotto SaaS workspace su una sola tabella. Gli Item usano PK = "WS#<id>"
e SK sovraccaricata per 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 |
Ora il prodotto vuole i commenti sui documenti, più una nuova lettura: "elenca ogni commento che un membro ha scritto nel workspace, più recenti prima." Quest'ultima clausola è la migrazione. Un nuovo tipo di entità da solo è banale; servire una query a cui le chiavi attuali non possono rispondere è il lavoro.
Aggiungi prima il nuovo tipo di entità
I commenti sono semplicemente nuovi Item nella stessa partizione — nessuna cerimonia di migrazione, nessuna nuova tabella:
| PK | SK | attributes |
|---|---|---|
| WS#a91 | DOC#2026-04-01#x7#CMT#01HZ... | author, text, createdAt |
Una Query su PK = "WS#a91" con SK begins_with "DOC#2026-04-01#x7#CMT#"
elenca già i commenti di un documento. I documenti esistenti restano intatti. Questa
metà fa il deploy il giorno uno — vedi item collection e chiavi sovraccaricate
per il perché la stessa partizione contiene entrambi.
La nuova query ha bisogno di un GSI
"Tutti i commenti di un membro, più recenti prima" non può essere servito dalla tabella base —
memberId non è né la PK né un prefisso SK. È un nuovo indice, e
sceglierlo correttamente è una sua decisione: vedi GSI vs LSI
(un LSI deve esistere alla creazione della tabella, quindi per una migrazione su una tabella live un GSI
è la tua unica opzione).
Aggiungi un GSI1 generico e scrivi i nuovi attributi sui nuovi Item commento:
| GSI1PK | GSI1SK |
|---|---|
| MEMBER#u44 | 2026-04-02T09:15:00Z |
Query GSI1 WHERE GSI1PK = "MEMBER#u44" con ScanIndexForward = false dà
commenti più recenti prima per membro.
Costruisci l'indice online
UpdateTable aggiunge un GSI a una tabella live senza downtime. DynamoDB fa il backfill
degli Item esistenti nell'indice in background; l'indice riporta
CREATING/backfilling finché non è fatto, poi passa a ACTIVE
(Managing GSIs).
Due trappole qui. Primo, AWS avverte che aggiungere un GSI può mettere in throttling le scritture
della tabella base se la nuova chiave distribuisce in modo non uniforme — aggiungilo in una finestra a
basso traffico e osserva CloudWatch. Secondo, l'indice è eventualmente coerente anche dopo
che diventa ACTIVE; una scrittura può non essere visibile sul GSI per un momento. Vedi
perché i GSI sono eventualmente coerenti.
Fai il backfill dei vecchi Item
Il GSI indicizza solo Item che hanno GSI1PK/GSI1SK. I tuoi commenti
pre-migrazione — scritti prima che l'attributo esistesse — non compaiono mai, nemmeno dopo
il backfill. Il backfill online del GSI copia gli Item esistenti, ma non può
inventare attributi che non sono su di essi. Devi aggiungere i valori.
Due strategie:
| Strategia | Come funziona | Usa quando |
|---|---|---|
| Lazy | In lettura di un vecchio Item, riscrivi i nuovi attributi | I vecchi Item sono letti spesso; spalma il costo |
| Sweep | Uno Scan paginato aggiorna ogni vecchio Item una volta | Ti serve il GSI completo entro una scadenza |
Per lo sweep, pagina con Scan, e per ogni vecchio commento aggiungi gli attributi
dell'indice con un UpdateItem condizionale così non calpesti mai una scrittura
concorrente.
La condizione protegge sull'attributo non già esistente. Costruisci e copia la
ConditionExpression e l'UpdateExpression esatte con il
DynamoDB Expression Builder invece di
digitare a mano attribute_not_exists(GSI1PK).
Dual-write durante la transizione
Finché ogni vecchio Item non porta i nuovi attributi, due forme coesistono. Il percorso di scrittura deve popolare il nuovo formato a ogni scrittura — nuovi commenti e ogni update a uno vecchio — così il gap si restringe soltanto.
Scegli una condizione di fine backfill che puoi verificare: lo sweep ha paginato l'intera tabella, oppure il percorso lazy è girato abbastanza a lungo che gli Item non convertiti sono obsoleti per design. Solo allora rimuovi il vecchio percorso di lettura. Saltare questo è come una migrazione "si completa" mentre una frazione di query restituisce silenziosamente risultati corti.

Errori
- Aggiungere l'attributo ≠ backfillato. Un nuovo GSI parte vuoto per i vecchi Item. Verifica la copertura prima di fidarti della query.
- Cambiare una chiave sul posto non è una migrazione — è una riscrittura. Non puoi
mutare la
PK/SKdi un Item; scrivi un nuovo Item sotto la nuova chiave ed elimini quello vecchio. Pianificalo come copy-then-delete, con dual-read nel mezzo. - Nessun cutover transazionale. Non c'è momento in cui l'intera tabella si ribalta. Progetta ogni passo perché sia sicuro mentre entrambe le forme sono live.
Prossimi passi
Verifica le nuove chiavi e le collection sovraccaricate in single-table design, e conferma che il backfill è completo paginando la tabella live. Prova DynoTable per navigare la tua tabella, individuare gli Item non backfillati ed eseguire gli update condizionali sui tuoi dati.


