DynamoDB-Migrationen ohne Downtime
Aus SQL ist eine Migration ein ALTER TABLE, das die Tabelle sperrt, während es
jede Row umschreibt. DynamoDB hat kein Schema zum Ändern — Items sind schemaless,
also ist ein Attribut oder ein neuer Entity-Typ gratis hinzuzufügen.
Der harte Teil ist das Access Pattern, das die neuen Daten bedienen müssen, und Live-Daten so umzuformen, dass sie es bedienen — ohne Stop-the-World-Rewrite.
Wie migrierst du eine DynamoDB-Tabelle ohne Downtime?
DynamoDB hat kein ALTER TABLE, also sperren Migrationen die Tabelle nie. Du
fügst Attribute, eine neue Key-Form oder einen neuen online mit
UpdateTable hinzu und formst Live-Daten inkrementell um: alte Items lazy on
Read oder mit gedrosseltem Sweep backfüllen, und während des Übergangs beide
Formate dual-writen. Es gibt keinen Flag-Day-Cutover.
- Es gibt kein
ALTER TABLE. Items sind schemaless. Eine „Migration“ heißt Attribute, eine neue Key-Form oder einen neuen Index hinzufügen — nie ein fixes Column-Set umschreiben. - Neue Writes sind leicht; alte Items sind das Problem. Die bestehenden Rows tragen die neuen Attribute nicht, also verfehlt jeder neue Index oder jede neue Query sie still, bis du backfüllst.
- Indexes online hinzufügen, lazy backfüllen.
UpdateTablebaut einen GSI auf einer Live-Tabelle; backfülle alte Items on Read (lazy) oder mit kontrolliertem Sweep — nie Flag-Day-Cutover. - Dual-Write über den Übergang. Solange beide Formen koexistieren, schreibe altes und neues Format zusammen, damit kein Read-Pfad veraltet.
Als Access Pattern framen, nicht als Spalte
Angenommen, du betreibst ein SaaS-Workspace-Produkt auf einer Tabelle. Items
nutzen PK = "WS#<id>" und SK pro Entity:
| 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 |
Jetzt will Product Comments auf Documents, plus einen neuen Read: „liste jeden Comment, den ein Member workspace-weit geschrieben hat, neueste zuerst.“ Dieser letzte Satz ist die Migration. Ein neuer Entity-Typ allein ist trivial; eine Query zu bedienen, die die aktuellen Keys nicht beantworten können, ist die Arbeit.
Zuerst den neuen Entity-Typ hinzufügen
Comments sind einfach neue Items in derselben Partition — keine Migrationszeremonie, keine neue Tabelle:
| PK | SK | attributes |
|---|---|---|
| WS#a91 | DOC#2026-04-01#x7#CMT#01HZ... | author, text, createdAt |
Eine Query auf PK = "WS#a91" mit SK begins_with "DOC#2026-04-01#x7#CMT#"
listet schon die Comments eines Documents. Bestehende Documents bleiben unberührt.
Diese Hälfte shipped am Tag eins — siehe
Item Collections und überladene Keys, warum
dieselbe Partition beides hält.
Die neue Query braucht einen GSI
„Alle Comments eines Members, neueste zuerst“ kann die Base Table nicht bedienen
— memberId ist weder der PK noch ein SK-Prefix. Das ist ein neuer Index, und
ihn richtig zu wählen ist eine eigene Entscheidung: siehe
GSI vs LSI (ein LSI muss bei Table Creation existieren,
also ist für eine Migration auf einer Live-Tabelle ein GSI deine einzige Option).
Füge einen generischen GSI1 hinzu und schreibe die neuen Attribute auf neue
Comment-Items:
| GSI1PK | GSI1SK |
|---|---|
| MEMBER#u44 | 2026-04-02T09:15:00Z |
Query GSI1 WHERE GSI1PK = "MEMBER#u44" mit ScanIndexForward = false liefert
neueste-zuerst Comments pro Member.
Den Index online bauen
UpdateTable fügt einen GSI einer Live-Tabelle ohne Downtime hinzu. DynamoDB
backfüllt bestehende Items im Hintergrund in den Index; der Index meldet
CREATING/backfilling bis fertig, dann flippt er zu ACTIVE
(Managing GSIs).
Zwei Fallen hier. Erstens warnt AWS, dass das Hinzufügen eines
Base-Table-Writes drosseln kann, wenn der neue Key ungleich verteilt —
füge ihn in einem Low-Traffic-Fenster hinzu und schau CloudWatch. Zweitens ist
der Index , selbst nachdem er
ACTIVE ist; ein Write kann einen Moment auf dem GSI unsichtbar sein. Siehe
warum GSIs eventuell konsistent sind.
Die alten Items backfüllen
Der GSI indexiert nur Items, die GSI1PK/GSI1SK haben. Deine
Pre-Migration-Comments — geschrieben, bevor das Attribut existierte — erscheinen
nie, selbst nachdem Backfill fertig ist. Online-GSI-Backfill kopiert bestehende
Items, kann aber Attribute nicht erfinden, die nicht auf ihnen liegen. Du musst
die Werte hinzufügen.
Zwei Strategien:
| Strategie | Wie sie funktioniert | Nutzen wenn |
|---|---|---|
| Lazy | Beim Read eines alten Items die neuen Attribute zurückschreiben | Alte Items werden oft gelesen; Kosten tröpfeln |
| Sweep | Ein paginierter Scan updated jedes alte Item einmal | Der GSI muss bis Deadline komplett sein |
Für den Sweep page mit Scan durch, und für jeden alten Comment füge die
Index-Attribute mit conditional UpdateItem hinzu, damit du nie einen
concurrent Write überschreibst.
Die Condition schützt darauf, dass das Attribut noch nicht existiert. Baue und
kopiere die exakte ConditionExpression und UpdateExpression mit dem
DynamoDB Expression Builder, statt
attribute_not_exists(GSI1PK) handzutippen.
Dual-Write durch den Übergang
Bis jedes alte Item die neuen Attribute trägt, koexistieren zwei Formen. Der Write-Pfad muss das neue Format bei jedem Write befüllen — neue Comments und jedes Update an einem alten — damit die Lücke nur schrumpft.
Wähle eine Backfill-Endbedingung, die du verifizieren kannst: der Sweep hat die ganze Tabelle gepaged, oder der Lazy-Pfad lief lange genug, dass unkonvertierte Items by Design stale sind. Erst dann entfernst du den alten Read-Pfad. Das zu überspringen ist, wie eine Migration „fertig“ wird, während ein Bruchteil der Queries still zu kurze Results liefert.

Fallstricke
- Attribut hinzufügen ≠ backgefüllt. Ein neuer GSI startet für alte Items leer. Verifiziere Coverage, bevor du der Query vertraust.
- Einen Key in Place ändern ist ein Rewrite. Du kannst den
PK/SKeines Items nicht mutieren; du schreibst ein neues Item unter dem neuen Key und löschst das alte. Plane es als Copy-then-Delete, Dual-Read dazwischen. - Kein transaktionaler Cutover. Es gibt keinen Moment, in dem die ganze Tabelle flippt. Designe jeden Schritt so, dass er sicher ist, während beide Formen live sind.
Nächste Schritte
Sanity-check die neuen Keys und überladenen Collections in Single-Table Design, und bestätige, dass das Backfill komplett ist, indem du die Live-Tabelle pagest. Probier DynoTable, um deine Tabelle zu browsen, un-backgefüllte Items zu finden und die conditional Updates gegen deine eigenen Daten zu fahren.


