Fortgeschritten5 Min. Lesezeit

Zusammengesetzte Sort Keys in DynamoDB

Ein ist ein Partition Key plus ein Sort Key. Der Trick, der ihn mächtig macht, steckt im Sort Key: kodiere eine Hierarchie als einen delimited String, und eine einzelne Query liest einen ganzen Teilbaum in Sortierreihenfolge — keine Joins, keine Rekursion, kein zweiter Round-Trip.

Wie funktionieren zusammengesetzte Sort Keys in DynamoDB?

Ein zusammengesetzter Sort Key packt eine Hierarchie in einen delimited String — root/photos/2026/ — den DynamoDB in UTF-8-Byte-Reihenfolge speichert. Weil das Layout schon dem Baum entspricht, liest eine einzelne Query mit begins_with(SK, "root/photos/") einen ganzen Teilbaum in Pfadreihenfolge. Keine Joins, keine Rekursion, kein zweiter Round-Trip — nur ein Prefix-Scan über einen zusammenhängenden .

  • Der Sort Key ist ein sortierbarer String, nicht nur eine ID. Packe einen Pfad hinein — root/photos/2026/ — und DynamoDB speichert die Items der Partition automatisch in UTF-8-Byte-Reihenfolge.
  • Ein Delimiter macht aus Prefix-Matches Teilbaum-Reads. begins_with(SK, "root/photos/") liefert jeden Nachfahren dieses Ordners in einer Query.
  • Sort Keys unterstützen Range-Bedingungen, keine beliebigen Filter. Du bekommst begins_with, between, >, < — designe den Key so, dass der benötigte Read ein Prefix oder eine Range ist, kein Scan.
  • Der Delimiter trägt Last. Wähle einen, der in einem Pfadsegment nicht vorkommen kann, sonst kollidieren zwei unabhängige Äste.

Warum der Sort Key das ganze Spiel ist

Aus SQL würdest du einen Ordnerbaum mit Self-Join über parent_id modellieren und rekursiv laufen — eine Query pro Ebene. In DynamoDB ist das ein N+1-Fallstrick gegen einen Key-Value-Store ohne Joins.

DynamoDB speichert jedes Item unter einem Partition Key sortiert nach seinem Sort Key, bei Strings in UTF-8-Byte-Reihenfolge (AWS: Query key conditions). Wenn dein Sort Key der Pfad ist, entspricht das physische Layout schon dem Baum. Ein Read wird zum Prefix-Scan über einen zusammenhängenden Slice — kein Graph-Walk.

Das ist die Verschiebung: der Sort Key ist kein Identifier, den du exakt matchst. Er ist eine sortierbare Adresse. Designe ihn, und die Query fällt kostenlos heraus.

Einen Dateisystem-Baum modellieren

Angenommen, du speicherst Dateibäume pro Account. Ein Drive pro Account ist die natürliche Partition; der Pfad darin ist der Sort Key.

PKSKnode_typebytes
DRIVE#a91root/folder-
DRIVE#a91root/docs/folder-
DRIVE#a91root/docs/taxes.pdffile88210
DRIVE#a91root/photos/folder-
DRIVE#a91root/photos/2026/folder-
DRIVE#a91root/photos/2026/beach.jpgfile284910
DRIVE#a91root/photos/2026/sunset.jpgfile512004

Zwei Konventionen leisten hier die Arbeit:

  • PK = DRIVE#<account> hält den ganzen Baum eines Accounts in einer einzigen , sodass jeder Teilbaum-Read eine Single-Partition-Query ist.
  • SK ist der volle Pfad mit einem trailing / bei Ordnern. Der Slash am Ende ist Absicht — er lässt einen Ordner vor seinen eigenen Kindern sortieren und hält root/photos/ von einer Geschwisterdatei namens root/photos getrennt.

Einen Teilbaum in einer Query lesen

Alles unter root/photos/ auflisten — Ordner, Unterordner und Dateien, rekursiv:

Query
KeyConditionExpression = PK = :drive AND begins_with(SK, :prefix)
:drive   = "DRIVE#a91"
:prefix  = "root/photos/"

Das liefert root/photos/, root/photos/2026/, beach.jpg und sunset.jpg — in Pfadreihenfolge, in einem abgerechneten Read. Du zahlst nur für die Items in diesem Slice, nicht für den ganzen Drive.

In DynoTable führst du genau diese begins_with-Query gegen den Path-Sort-Key aus, und der Ordner plus seine Nachfahren kommen in Pfadreihenfolge zurück — keine Placeholder-Syntax zum Handschreiben.

Brauchst du den rohen KeyConditionExpression (Namen, Werte und begins_with) für deinen eigenen Code? Baue und kopiere ihn im DynamoDB Expression Builder.

Eine begins_with-Query auf dem Path-Sort-Key in DynoTable — Ordner und Nachfahren in Pfadreihenfolge.
Eine begins_with-Query auf dem Path-Sort-Key in DynoTable — Ordner und Nachfahren in Pfadreihenfolge.

Eine Ebene listen, nicht den ganzen Teilbaum

begins_with gibt dir den rekursiven Read. Für ein nicht-rekursives Verzeichnislisting — die unmittelbaren Kinder von root/photos/ und nichts tiefer — speichere ein depth-Attribut und füge eine Sort-Key-Range plus Filter hinzu, oder splittet den Pfad in einen parent-GSI. Die einfachste Version: behalte ein parent-Attribut (root/photos/) und einen GSI darauf geschlüsselt.

Ein Sort Key beantwortet Prefix- und Range-Fragen günstig. „Nur direkte Kinder“ ist eine andere Frage — modelliere sie explizit, statt zu hoffen, eine FilterExpression mache sie effizient. Ein Filter läuft nach dem Read und du zahlst für jedes verworfene Item.

Den Delimiter sorgfältig wählen

Der Delimiter ist Teil deines Datenvertrags. Zwei Regeln:

  • Er darf nie innerhalb eines Pfadsegments vorkommen. Können Dateinamen / enthalten, ist / der falsche Delimiter — eine Datei a/b ist nicht von einem Ordner a mit b zu unterscheiden. Nimm ein reserviertes Byte (manche Teams nutzen # oder ein Control-Char) und verbiete es in Segmenten.
  • Achte auf die Sortierreihenfolge an Grenzen. / (0x2F) sortiert vor Ziffern und Buchstaben — meist das, was du für Baumordnung willst. Ändere den Delimiter und du änderst die Ordnung — prüfe das gegen echte Daten.

Zusammengesetzter Sort Key vs. separates Sort-Attribut

Zusammengesetzter Sort Key (root/photos/2026/x)Plain-ID-Sort-Key + parent-Attribut
Teilbaum-ReadEine begins_with-QueryRekursive Queries (N+1) oder GSI-Walk
OrdnungPfadordnung, gratisExplizites Sort-Attribut nötig
Move / RenameAlle Nachfahren umschreibenEinen parent-Pointer updaten
Direkte-Kinder-ListeBraucht depth-Attr oder GSINatürlich (parent = x)

Zusammengesetzte Keys gewinnen, wenn Reads teilbaumförmig sind und Ordnung zählt; das Flat-ID-Modell gewinnt, wenn der Baum ständig mutiert. Die meisten read-heavy Hierarchien — Dateibäume, Kategoriebäume, Org-Charts — neigen zum Composite.

Fallstricke und nächste Schritte

  • Überfülle den Key nicht. Alles, was du kodierst, ist unveränderlich und nur per Prefix indexiert. Attribute, die du per Equality abfragst, gehören in eigene Felder oder einen GSI — nicht in den Sort Key gestopft.
  • Ein Sort Key kann kein beliebiges WHERE. Nur begins_with, between und Vergleiche. Greifst du nach einer FilterExpression, hast du den Key wahrscheinlich falsch modelliert — siehe Query vs. Scan.
  • Tieferes Key-Design lebt in Single-Table Design; wenn ein Teilbaum-Read einen Index statt der Base Table braucht, siehe GSI vs. LSI.

Baue die begins_with-Key-Condition mit dem Expression Builder, dann lade DynoTable herunter, um diese Prefix-Queries gegen deine eigenen Tabellen zu fahren und einen Teilbaum in Pfadreihenfolge zurückzukommen zu sehen. (Und der Self-JOIN, den du in SQL zurückgelassen hast? DynoTables SQL Workbench führt ihn weiterhin aus, wenn du ihn brauchst.)

Aktualisiert

Probiere dieses Design interaktiv aus

Skizziere deine Entitäten und Zugriffsmuster im kostenlosen DynamoDB Single-Table Design Tool — es schlägt PK/SK-Schlüsselvorlagen vor, zeigt eine Vorschau der Item-Collections und zeigt, welche Muster einen GSI brauchen.

Single-Table Design Tool öffnen