DynamoDB Key Condition Expressions
Eine Key Condition Expression ist die KeyConditionExpression, die du an eine
Query übergibst — der einzige Teil der Anfrage, den DynamoDB verwendet, um Items
zu finden. Alles andere (Filter, Projektionen) läuft, nachdem der Read schon
gemessen ist.
Was ist eine Key Condition Expression in DynamoDB?
Eine Key Condition Expression ist die KeyConditionExpression einer Query, die DynamoDB mitteilt, welche Items gelesen werden sollen. Der muss eine Gleichheit sein (PK = :v); der nimmt einen Range-Operator — =, <, <=, >, >=, BETWEEN oder begins_with. Sie entscheidet, was gelesen und abgerechnet wird — anders als ein Filter.
- Der Partition Key muss eine Gleichheit sein.
PK = :vund nichts sonst — keine Ranges, keinbegins_with, keinIN. DynamoDB hasht ihn, um eine Partition zu lokalisieren. - Der Sort Key nimmt einen Range-Operator.
=,<,<=,>,>=,BETWEENoderbegins_with— hier schneidest du eine Item Collection. - Es ist kein Filter. Eine Key-Condition entscheidet, was gelesen und
abgerechnet wird; eine
FilterExpressionstutzt nur das Ergebnis, nachdem du für den Read bezahlt hast. - Sort Keys sind byte-geordnet. Range-Operatoren vergleichen lexikografisch, also ist die Art, wie du den Sort-Key-String formatierst, deine Query-Power.
Warum der Partition Key auf Gleichheit festgelegt ist
DynamoDB speichert Items, indem es den Partition Key auf eine physische Partition hasht. Ein Hash gibt dir einen Ort, keine Range — also gibt es nichts, quer durchzuscannen.
Darum werden PK > :v oder begins_with(PK, :v) rundweg abgelehnt. Die Engine
kann "alle Partitionen, deren Key mit X beginnt" nicht beantworten, ohne die ganze
Tabelle zu lesen, was genau der Scan ist, den zu vermeiden sie gebaut ist.
Aus SQL kommend fühlt sich das rückwärts an: WHERE id LIKE 'order%' ist in
Postgres trivial. In DynamoDB ist der Partition Key eine Adresse, keine
durchsuchbare Spalte.
Der Sort Key ist, wo die Macht liegt
Innerhalb einer Partition werden Items nach Sort Key sortiert gespeichert. Diese Ordnung ist es, die Range-Operatoren ausnutzen — DynamoDB sucht zu einer Position und liest vorwärts.
| Operator | Liest | Verwende es für |
|---|---|---|
SK = :v | Ein exaktes Item | Ein bestimmtes Kind per Key |
SK < / <= / > / >= :v | Eine offene Scheibe | "Alles nach diesem Punkt" |
SK BETWEEN :a AND :b | Eine geschlossene Range (inklusiv) | Ein begrenztes Fenster — eine Datumsspanne |
begins_with(SK, :p) | Eine Präfix-Scheibe | Ein Typ oder eine Hierarchie unter dem PK |
Es gibt kein LIKE, kein CONTAINS, kein ENDS_WITH auf dem Key. Substring- und
Suffix-Matching sind nicht byte-geordnet, also würden sie einen vollen Read
erzwingen — by Design lässt die API das nicht zu. Die leben in FilterExpression,
wo du schon bezahlt hast. (AWS: Key Condition Expressions)
Ein durchgespieltes Beispiel: Nachrichten in einer Chat-App
Angenommen, du baust kanal-basierten Chat. Eine Tabelle, nach Kanal partitioniert, nach Nachrichtenzeit sortiert. Eigenes Key-Schema:
- Partition Key
ChannelRef—CH#{channelId} - Sort Key
PostedAt— ein ISO-8601-Zeitstempel,MSG#2026-06-23T14:05:00Z
Der MSG#-Präfix hält Nachrichtenzeilen sortierbar und unterscheidbar von jedem
anderen Zeilentyp, den du unter demselben Kanal ko-lokalisieren könntest (gepinnte
Config, Mitgliedschaft).
Lade die jüngsten Nachrichten eines Kanals. Nur der Partition Key, neueste zuerst:
KeyConditionExpression: ChannelRef = :ch
ExpressionAttributeValues: { ":ch": "CH#general" }
ScanIndexForward: falseScanIndexForward: false läuft die sortierte Collection rückwärts ab — der billige
Weg, "neueste zuerst" zu bekommen, ohne clientseitig zu sortieren.
Ein bestimmter Tag mit begins_with. Weil der Zeitstempel der Sort Key ist und
er als Text gespeichert wird, ist ein Datums-Präfix eine saubere Scheibe:
KeyConditionExpression ChannelRef = :ch AND begins_with(PostedAt, :day)
:ch "CH#general"
:day "MSG#2026-06-23"
Das liest jede Nachricht am 2026-06-23 und nichts sonst — DynamoDB sucht zum Präfix und stoppt, wenn es vom Ende fällt. Das funktioniert nur, weil der Präfix ein echter Links-Anker eines byte-sortierten Strings ist.
Ein präzises Fenster mit BETWEEN. Für "die Nachrichten während der
14:00-Stunde" schlägt eine inklusive Range einen Präfix:
KeyConditionExpression ChannelRef = :ch AND PostedAt BETWEEN :lo AND :hi
:ch "CH#general"
:lo "MSG#2026-06-23T14:00:00Z"
:hi "MSG#2026-06-23T14:59:59Z"
BETWEEN ist auf beiden Grenzen inklusiv, also wähle deine Endpunkte bewusst — ein
Off-by-One hier droppt oder verdoppelt still eine Randnachricht.
Du kannst jede dieser Expressions zusammenbauen und kopieren, mit der für dich
ausgefüllten ExpressionAttributeValues-Map, im
DynamoDB Expression Builder — praktisch, um
die begins_with- und BETWEEN-Syntax beim ersten Mal richtig hinzubekommen.
Sieh es in DynoTable
Führe dieselbe Key-Condition gegen eine echte Kanal-Partition aus und sieh zu, wie die verbrauchte Kapazität live aktualisiert wird, sodass du bestätigen kannst, dass du eine Scheibe liest — nicht die ganze Collection.
Die Falle: eine Key-Condition mit einem Filter verwechseln
Der teure Fehler ist, zu FilterExpression zu greifen, um die Arbeit eines Keys zu
machen.
KeyConditionExpression: ChannelRef = :ch
FilterExpression: begins_with(PostedAt, :day)Das sieht äquivalent zur begins_with-Key-Condition oben aus und gibt dieselben
Zeilen zurück — aber es liest zuerst die ganze Kanal-Partition, dann verwirft
es alles außerhalb des Tages. Du wirst für den vollen Read abgerechnet.
Filter reduzieren nie die Read-Kosten. Sie laufen, nachdem DynamoDB die Items
gemessen hat, dieselbe Falle wie ein gefilterter Scan.
Wenn ein Prädikat in die Key-Condition kann, gehört es dorthin.
Der Fix ist upstream: wenn ein Zugriffsmuster nicht als eine PK-Gleichheit plus eine Sort-Key-Range ausgedrückt werden kann, ist das ein Modellierungssignal. Forme entweder den Sort Key um oder füge einen für das Muster gekeyten Index hinzu — siehe GSI vs. LSI und Single-Table Design dafür, wie du die Keys auslegst.
Fallstricke und nächste Schritte
- Partition Key ist immer
=. Keine Ranges, niemals. Wenn du eine Range über Partitionen hinweg brauchst, bist du über eine einzelneQueryhinausgewachsen. - Eine Sort-Key-Bedingung pro Query. Du kannst nicht zwei Sort-Key-Prädikate
ANDen; wähleBETWEENoderbegins_with, nicht beide. - Reservierte Wörter brauchen Aliase. Ein Key namens
TimestampoderNamemussExpressionAttributeNames(#ts) verwenden, sonst gibt die Query einen Fehler. (AWS: reservierte Wörter) BETWEENist inklusiv. Beide Endpunkte werden gematcht — entwirf deine Grenzen entsprechend.
Entwirf deine Key-Conditions im Expression Builder, dann probier DynoTable, um sie gegen deine eigenen Tabellen auszuführen und zuzusehen, welche Kapazität sie tatsächlich verbrauchen.