Fortgeschritten7 Min. Lesezeit

DynamoDB nach einem sich ändernden Attribut sortieren

Du modellierst einen Sort Key um ein Attribut, um Items in seiner Ordnung zu querien — dann ändert sich das Attribut. Der Status eines Tickets, der State einer Order, die Priority einer Task. DynamoDBs Regel: du kannst ein Key-Attribut nicht in Place updaten. Ein Primary Key ist für die Lebensdauer des Items immutable. Ändere einen Wert, der Teil des Keys ist, und du editierst kein Item — du bewegst es, und DynamoDB lässt dich das explizit tun.

Kannst du einen DynamoDB-Sort-Key ändern?

Nein. Ein Sort Key ist Teil des Primary Key, und DynamoDB-Key-Attribute sind immutable — UpdateItem kann keinen Partition- oder Sort-Key-Wert editieren, und es gibt keine „Move Item“-Operation. Um ihn zu ändern, lösche das alte Item und putte ein neues, oder halte den volatilen Wert stattdessen auf einem GSI-Sort-Key.

  • Key-Attribute sind immutable. Du kannst keinen Partition- oder Sort-Key- Wert UpdateItemen — DynamoDB hat keine „Move Item“-Operation.
  • Um einen Key-Wert zu ändern, löschst du das alte Item und puttest ein neues — idealerweise in einer Transaction, damit es atomar ist.
  • Besser: halte den volatilen Wert vom Base-Table-Key fern und lege ihn auf einen GSI-Sort-Key — GSI-Keys können sich ändern, weil das Updaten des Base-Items den Index-Eintrag nur neu propagiert.
  • Wähle Sort Keys, die sich nicht ändern (Timestamps, immutable Ids), wann immer das Access Pattern es erlaubt.

Das Problem: ein Status, nach dem du sortieren willst, der sich ständig ändert

Angenommen, du betreibst einen Support-Desk und willst Tickets eines Teams nach Status geordnet listen, also legst du Status in den Sort Key:

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

Jetzt bewegt sich das Ticket zu pending. Du würdest gerne einfach den Sort Key per UpdateItem auf STATUS#pending#TICKET#8842 setzen — aber DynamoDB rejectet jeden Write, der ein Key-Attribut ändert. Der Key ist die Adresse des Items; du kannst die Adresse nicht in Place editieren. Der Status, nach dem du sortieren wolltest, ist genau das, was nicht stillsitzt.

Option 1: löschen und neu erstellen (atomar)

Wenn der Wert im Base-Table-Key leben muss, heißt ihn zu ändern, das alte Item zu entfernen und das neue zu schreiben:

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

Tu es in einem TransactWriteItems, sodass Delete und Put entweder beide succeeden oder beide failen — sonst verliert ein Crash dazwischen das Ticket oder dupliziert es. Das funktioniert, aber jede Status- Änderung sind jetzt zwei Writes plus eine Transaction; fine für gelegentliche Änderungen, teuer für heiße.

Option 2: den mutablen Wert vom Base-Key fernhalten (bevorzugt)

Mach den Base-Table-Key etwas Immutables (die Ticket-Id) und lege den volatilen, sortierbaren Wert auf einen GSI-Sort-Key.

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

Status zu ändern ist jetzt ein plaines UpdateItem auf dem status-Attribut des Base-Items — das DynamoDB erlaubt, weil status kein Base-Table-Key ist. DynamoDB propagiert den GSI-Eintrag dann automatisch neu an seine neue sortierte Position. Ein API-Call, mit Atomicity für dich gehandelt — keine Transaction, kein Delete-Tanz (unter der Haube löscht DynamoDB trotzdem den alten Index-Eintrag und schreibt den neuen, also kostet eine indexierte Änderung ~3 Write Units gegen ~4 einer transactional Delete-and-Put).

JaNein, es ist ein GSI-Sort-KeyStatus wechselt open zu pendingLiegt der Wert in einemBase-Table-Key?Delete + Recreate in einerTransactionPlaines UpdateItem; GSIpropagiert neu

Der GSI ist eventuell konsistent und kostet extra Storage/Writes — aber für einen Wert, der sich oft ändert, ist das etwas günstiger (~3 vs 4 Write Units) und viel einfacher als Delete-and-Recreate bei jeder Änderung.

Die Keys in DynoTable designen

Baue und preview die Key Conditions für den Base-Read und den GSI-Read im DynamoDB Expression Builder.

In DynoTable wählst du dann, durch welchen Index eine Query läuft, und siehst den volatilen Wert auf dem GSI sortieren, während das Base-Item seinen immutable Key behält — beide Reads Side by Side auf echten Daten.

Einen status-sortierten GSI querien, während das Base-Item einen immutable Key in DynoTable behält.
Einen status-sortierten GSI querien, während das Base-Item einen immutable Key in DynoTable behält.

Fallstricke + nächste Schritte

  • Versuche nie, ein Key-Attribut zu UpdateItemen — es wird rejected; Key- Werte sind für die Lebensdauer des Items fix.
  • Wenn du es bewegen musst, tu Delete+Put in einer Transaction — nie als zwei ungeschützte Writes.
  • Bevorzuge immutable Base-Keys + einen GSI für jedes Attribut, nach dem du sortierst und das du mutierst.
  • Vergiss GSI Eventual Consistency nicht — der neu sortierte Eintrag erscheint nach einer kurzen Propagation-Verzögerung.
  • Verwandt: Sort-Key-Strategien, GSI vs LSI, Transactions.

Willst du sehen, wie ein mutables Attribut auf einem GSI versus der Base Table sortiert? Lade DynoTable herunter und erkunde deine Indexes direkt.

Write-Kosten: Delete-and-Put vs GSI-Update

Grobe WCU-Vergleiche für ein 1-KB-Ticket-Item in us-east-1 On-Demand (echte Abrechnung folgt AWS-Rounding-Regeln):

PatternAPI-CallsTypischer WCU-Impact
Transactional Delete + Put auf Base-KeyTransactWriteItems (2 Ops)~2× Item-Größe pro Op in Transaction-Pricing
status-Attribut updaten; GSI propagiert neuEin UpdateItemBase-Write + GSI-Write (~2 WCU für 1-KB-Item + projezierten Attrs)

Der GSI-Pfad vermeidet Application-Level-Orchestrierung und eliminiert das Fenster, in dem ein Crash zwischen Delete und Put die Row verliert. Du tauschst Eventual Consistency auf dem Index-Read gegen einfachere Writes.

Modelliere deine Item-Größe und Update-Rate im Pricing Calculator, wenn Status-Änderungen viele Male pro Minute feuern.

Sparse GSI für status-sortierte Listen

Wenn nur offene Tickets eine status-sortierte Queue brauchen, nutze einen Sparse Index: schreibe GSI1PK = TEAM#7 und GSI1SK = STATUS#open#... nur solange status = open. Wenn das Ticket schließt, entferne oder omitte die GSI-Key-Attribute beim Update — das Item fällt aus dem Index, ohne Delete-and-Put auf dem Base-Sort-Key.

Das hält den Index klein und vermeidet, geschlossene Tickets zu indexieren, die du nie listest.

Immutable Base-Keys, die du bevorzugen solltest

Volatiles FeldBase-Table-SKBesserer Base-SKVolatiles Feld lebt auf
Order-StatusSTATUS#shipped#ORD#99ORD#99GSI-Sort oder Attribut
Task-PriorityP#1#TASK#12TASK#12GSI-Sort
User Display NameNAME#alice#USER#5USER#5Non-Key-Attribut

Timestamps und immutable Ids (CREATED#2026-06-27T10:00:00Z, TICKET#8842) machen stabile Base-Sort-Keys, wenn du chronologische Ordnung auf der Base Table selbst brauchst.

Designe den GSI vor dem Coding

Mappe Access Patterns im Single-Table-Design-Tool — gib „liste offene Tickets per Team, Priority-Ordnung“ ein und inspiziere die vorgeschlagenen GSI1PK-/GSI1SK-Templates. Dann baue die Key Condition im Expression Builder und emitte eine paginierte Query mit dem Query Builder für Integrationstests.

Read-your-writes nach Status-Änderung

Nach UpdateItem zeigt ein stark konsistenter Read auf der Base Table den neuen status sofort. Eine Query auf dem GSI kann kurz nachhinken. UI-Flows, die zu einer GSI-sortierten Queue redirecten, sollten stale Rows tolerieren oder vom Base Table per Id re-fetchen, wenn Precision zählt.

Aktualisiert