Fortgeschritten5 Min. Lesezeit

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 = :v und nichts sonst — keine Ranges, kein begins_with, kein IN. DynamoDB hasht ihn, um eine Partition zu lokalisieren.
  • Der Sort Key nimmt einen Range-Operator. =, <, <=, >, >=, BETWEEN oder begins_with — hier schneidest du eine Item Collection.
  • Es ist kein Filter. Eine Key-Condition entscheidet, was gelesen und abgerechnet wird; eine FilterExpression stutzt 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.

OperatorLiestVerwende es für
SK = :vEin exaktes ItemEin bestimmtes Kind per Key
SK < / <= / > / >= :vEine offene Scheibe"Alles nach diesem Punkt"
SK BETWEEN :a AND :bEine geschlossene Range (inklusiv)Ein begrenztes Fenster — eine Datumsspanne
begins_with(SK, :p)Eine Präfix-ScheibeEin 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 ChannelRefCH#{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:  false

ScanIndexForward: 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 einzelne Query hinausgewachsen.
  • Eine Sort-Key-Bedingung pro Query. Du kannst nicht zwei Sort-Key-Prädikate ANDen; wähle BETWEEN oder begins_with, nicht beide.
  • Reservierte Wörter brauchen Aliase. Ein Key namens Timestamp oder Name muss ExpressionAttributeNames (#ts) verwenden, sonst gibt die Query einen Fehler. (AWS: reservierte Wörter)
  • BETWEEN ist 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.

Aktualisiert