DynamoDB Composite Primary Key: Partition Key + Sort Key erklärt
Ein zusammengesetzter Primärschlüssel besteht aus zwei Attributen: einem Partitionsschlüssel und einem Sortierschlüssel. Der Partitionsschlüssel bestimmt, wo ein Item liegt; der Sortierschlüssel ordnet die Items innerhalb dieser Partition.
Wenn du von SQL kommst, denk weniger an eine eindeutige id-Spalte und mehr an ein
GROUP BY partition, ORDER BY sort, das fest in der Tabelle verdrahtet ist.
Was ist ein zusammengesetzter Primärschlüssel in DynamoDB?
Ein zusammengesetzter Primärschlüssel in DynamoDB kombiniert zwei Attribute: einen Partitionsschlüssel
und einen Sortierschlüssel. Der Partitionsschlüssel bestimmt, in welcher physischen Partition ein Item
liegt; der Sortierschlüssel ordnet die Items innerhalb dieser Partition. Zusammen bilden sie die
eindeutige Identität des Items und lassen ein einzelnes Query einen sortierten Bereich statt
eines einzelnen Items zurückgeben.
- Zwei Teile, zwei Aufgaben. Der Partitionsschlüssel leitet das Item auf eine physische Partition; der Sortierschlüssel ordnet jedes Item, das diesen Partitionsschlüssel teilt.
- Eindeutig ist das Paar. Zwei Items dürfen denselben Partitionsschlüsselwert haben, solange sich ihre Sortierschlüssel unterscheiden — so hält eine Partition viele Zeilen.
- Der Sortierschlüssel ist der springende Punkt. Er ist es, der ein
Queryeinen Bereich (>=,between,begins_with) zurückgeben lässt statt eines Items, ganz ohneScan. - Schlüssel müssen Skalare sein. Partitions- und Sortierschlüssel können nur String, Zahl oder Binary sein — keine Maps, keine Listen (AWS docs).
Einfacher Schlüssel vs. zusammengesetzter Schlüssel
Ein einfacher Primärschlüssel ist nur ein Partitionsschlüssel. Er identifiziert ein Item
eindeutig, und du liest es mit GetItem zurück. Mehr nicht — keine Bereichs-Reads, kein
„gib mir die neuesten N".
Ein zusammengesetzter Schlüssel ergänzt den Sortierschlüssel, und genau dieser eine Zusatz macht, dass sich DynamoDB wie eine Datenbank anfühlt und nicht wie eine Hash-Map.
| Einfacher Schlüssel | Zusammengesetzter Schlüssel | |
|---|---|---|
| Attribute | Nur Partitionsschlüssel | Partitionsschlüssel + Sortierschlüssel |
| Eindeutigkeit | Partitionsschlüsselwert | Das Wertepaar |
| Mehrere Items pro Partition | Nein | Ja |
Bereich per Query | Nein (nur GetItem) | Ja (begins_with, between, >) |
| Passt natürlich zu | Suche per ID | Zeitreihen, Eins-zu-viele, Historie |
Eine Tabelle mit Sensormesswerten modellieren
Sagen wir, du sammelst Temperaturmesswerte von einer Flotte von Feldsensoren. Das Zugriffsmuster lautet „hol mir die Messwerte eines Geräts, neueste zuerst, innerhalb eines Zeitfensters". Das ist ein zusammengesetzter Schlüssel wie aus dem Lehrbuch.
Nimm die Geräte-ID als Partitionsschlüssel und den Zeitstempel des Messwerts als Sortierschlüssel:
| deviceId | readingTs | tempC | humidity |
|---|---|---|---|
| DEV#a1b2 | 2026-06-23T08:00:00Z | 21.4 | 48 |
| DEV#a1b2 | 2026-06-23T08:05:00Z | 21.7 | 47 |
| DEV#a1b2 | 2026-06-23T08:10:00Z | 22.1 | 46 |
| DEV#c9d8 | 2026-06-23T08:00:00Z | 19.8 | 55 |
Alle drei DEV#a1b2-Messwerte landen in derselben Partition, physisch zusammen
abgelegt und nach readingTs sortiert.
AWS nennt den Partitionsschlüssel das Hash-Attribut und den Sortierschlüssel das Range-Attribut — der Sortierschlüssel ist ein Bereich, innerhalb dessen du lesen kannst (AWS docs).
Unter jedem Partitionsschlüssel fallen die Items zu einer zusammen:
Ein einziges Query auf den Partitionsschlüssel liest jeden Messwert dieses Geräts,
bereits in Zeitstempel-Reihenfolge — kein Sortieren im Client, kein zweiter Roundtrip.
Was dieses Fenster kostet
Zehn Messwerte à 2 KB in der Partition ergeben 20 KB abgerechnetes Volumen. DynamoDB rundet
Reads pro 4-KB-Block auf, ein eventually consistent Query auf dieses Fenster kostet also
3 Read-Request-Einheiten (20 KB → fünf 4-KB-Blöcke × je 0,5 RCU). Ein
stark konsistenter Read auf dasselbe Fenster kostet 5 Einheiten (eine RCU pro Block).
Holst du dieselben zehn Zeilen mit zehn einzelnen GetItem-Aufrufen, greift die
Mindestens-ein-Block-Regel pro Item → 5 Einheiten eventually consistent, 10 stark
konsistent — die zusätzlichen Roundtrips noch gar nicht gerechnet.
| Lesemuster | Items | Berührte Daten | EC-Leseeinheiten |
|---|---|---|---|
Ein Query, readingTs zwischen Start und Ende | 10 | 20 KB | 3 |
10 × GetItem auf den vollen zusammengesetzten Key | 10 | 20 KB | 5 |
Nur Query auf die Partition, Feuchte in der App filtern | 10 | 20 KB | 3 |
Scan der Tabelle, Filter deviceId + Zeitfenster | alle | ganze Tabelle | tabellengroß |
Gib beim Prototyping ReturnConsumedCapacity: TOTAL mit; der
Preisrechner macht aus dieser Einheitenzahl einen
monatlichen Posten, sobald du deine Requests pro Sekunde kennst.
Frag den Bereich ab, scanne ihn nicht
Weil readingTs ein ISO-8601-String ist, sortiert er lexikografisch genauso wie
chronologisch. Ein Zeitfenster-Read ist damit ein Bereich in der Key Condition und
kein Filter:
Query
deviceId = "DEV#a1b2"
readingTs BETWEEN "2026-06-23T08:00:00Z" AND "2026-06-23T08:10:00Z"
Das ist eine KeyConditionExpression — sie schränkt den Read ein, bevor DynamoDB
Daten zurückgibt, du zahlst also nur für die Items im Fenster. Eine FilterExpression
läuft nach dem Read und stellt dir alles in Rechnung, was sie durchlaufen hat; das ist
der Scan-Fallstrick im Kleinen.
Die Expression selbst ist mit Platzhaltern und typisierten Werten von Hand fummelig zu
schreiben. Bau sie dir visuell im
DynamoDB Expression Builder und kopier die
exakte KeyConditionExpression in deinen SDK-Aufruf.
Entwirf den Sortierschlüssel mit Absicht
Der Sortierschlüssel ist der einzige Hebel für Bereichs-Reads, also forme ihn entlang deiner Abfragen.
- Nimm einen sortierbaren Zeitstempel. ISO-8601-Strings oder Epoch-Zahlen sortieren korrekt; rohe lokalisierte Datumsangaben nicht.
- Gib ihm ein Präfix für Eins-zu-viele-. Ein Sortierschlüssel wie
READING#2026-06-23T08:00:00Zlässt dich Entitätstypen unter einer Partition mischen und mitbegins_withwieder auseinanderschneiden. Das ist die Naht hin zum Single-Table Design. - Steck die Dimension mit hoher Kardinalität in den Partitionsschlüssel. Eine Sensor-ID hat
Tausende Werte und verteilt Writes damit gleichmäßig. Ein Partitionsschlüssel mit niedriger
Kardinalität (etwa
region) erzeugt eine .
Ein Partitionsschlüssel mit nur fünfzig unterschiedlichen Werten bündelt bei 10.000 Writes pro Sekunde ~200 WCU je logischer Partition, bevor DynamoDB splittet — im Prototyp in Ordnung, in Produktion schmerzhaft. Bevorzuge Bezeichner, die mit deiner Flotte mitwachsen (Geräte-ID, Mandanten-ID, Session-ID), gegenüber groben Gruppierungen — es sei denn, du platzierst absichtlich einen begrenzten Datensatz zusammen.
Wann dich ein zusammengesetzter Schlüssel beißt
Zusammengesetzte Schlüssel sind eine Festlegung. Du wählst einen Partitionsschlüssel, gehst live und entdeckst dann ein Zugriffsmuster, das eine andere Gruppierung braucht — „alle Messwerte über 30 °C über die ganze Flotte".
Die Basistabelle kann das nicht beantworten; der Partitionsschlüssel steht fest. Deine Optionen sind ein Global Secondary Index mit anderem Schlüssel oder ein Umbau.
Zähl deine Reads auf, bevor du dich auf das Schlüsselschema festlegst. Einen Primärschlüssel
zu ändern heißt Tabellenmigration, nicht ALTER TABLE.
Öffne in DynoTable den Tabellenbrowser und sieh dir eine Tabelle mit zusammengesetztem Schlüssel neben ihren GSIs an — die Sortierreihenfolge auf dem Sortierschlüssel ist Zeile für Zeile sichtbar, was um eins verschobene Zeitstempelformate auffliegen lässt, bevor sie in Produktion gehen.
Nächste Schritte
Zusammengesetzte Schlüssel sind das Fundament unter Item Collections, Eins-zu-viele-Beziehungen und den meisten brauchbaren Index-Designs — lies als Nächstes Single-Table Design und GSI vs. LSI, um zu sehen, wohin sie führen.
Skizzier deine KeyConditionExpression im
DynamoDB Expression Builder, lass dir das vollständige
paginierte Query im Query Builder ausgeben und
probier DynoTable aus, um deine echten Partitionen zu durchsuchen und die
Sortierreihenfolge gegen deine eigenen Tabellen zu prüfen.