Les key condition expressions DynamoDB
Une key condition expression est la KeyConditionExpression que tu passes à un
Query — la seule partie de la requête que DynamoDB utilise pour trouver les items.
Tout le reste (filtres, projections) s'exécute après que la lecture est déjà mesurée.
Qu'est-ce qu'une key condition expression dans DynamoDB ?
Une key condition expression est la KeyConditionExpression d'un Query qui indique à DynamoDB quels items lire. La doit être une égalité (PK = :v) ; la accepte un opérateur de plage — =, <, <=, >, >=, BETWEEN ou begins_with. C'est elle qui détermine ce qui est lu et facturé, contrairement à un filtre.
- La clé de partition doit être une égalité.
PK = :vet rien d'autre — pas de plages, pas debegins_with, pas deIN. DynamoDB la hache pour localiser une partition. - La clé de tri prend un opérateur de plage.
=,<,<=,>,>=,BETWEEN, oubegins_with— c'est là que tu découpes une item collection. - Ce n'est pas un filtre. Une condition de clé décide ce qui est lu et facturé ;
un
FilterExpressionne fait que rogner le résultat après que tu as payé la lecture. - Les clés de tri sont ordonnées par octets. Les opérateurs de plage comparent lexicographiquement, donc la façon dont tu formates la chaîne de clé de tri est ta puissance de requête.
Pourquoi la clé de partition est verrouillée sur l'égalité
DynamoDB stocke les items en hachant la clé de partition vers une partition physique. Un hachage te donne un emplacement, pas une plage — donc il n'y a rien à scanner à travers.
C'est pourquoi PK > :v ou begins_with(PK, :v) sont rejetés d'emblée. Le moteur ne
peut pas répondre à « toutes les partitions dont la clé commence par X » sans lire
toute la table, ce qui est exactement le Scan qu'il est conçu pour éviter.
Venant de SQL, ça semble à l'envers : WHERE id LIKE 'order%' est trivial dans
Postgres. Dans DynamoDB la clé de partition est une adresse, pas une colonne
cherchable.
La clé de tri est là où vit la puissance
Au sein d'une partition, les items sont stockés triés par la clé de tri. Cet ordonnancement est ce que les opérateurs de plage exploitent — DynamoDB se positionne puis lit vers l'avant.
| Opérateur | Lit | Sert pour |
|---|---|---|
SK = :v | Un item exact | Un enfant précis par sa clé |
SK < / <= / > / >= :v | Une tranche ouverte d'un côté | « Tout après ce point » |
SK BETWEEN :a AND :b | Une plage fermée (inclusive) | Une fenêtre bornée — une plage de dates |
begins_with(SK, :p) | Une tranche par préfixe | Un type ou une hiérarchie sous la PK |
Il n'y a pas de LIKE, pas de CONTAINS, pas de ENDS_WITH sur la clé. La
correspondance de sous-chaîne et de suffixe n'est pas ordonnée par octets, donc elle
forcerait une lecture complète — par conception, l'API ne te le laisse pas faire. Ceux-là
vivent dans FilterExpression, où tu as déjà payé. (AWS : Key condition expressions)
Un exemple travaillé : les messages d'une app de chat
Disons que tu construis un chat par canaux. Une table, partitionnée par canal, triée par heure de message. Schéma de clés original :
- Clé de partition
ChannelRef—CH#{channelId} - Clé de tri
PostedAt— un horodatage ISO-8601,MSG#2026-06-23T14:05:00Z
Le préfixe MSG# garde les lignes de message triables et distinctes de tout autre type
de ligne que tu pourrais co-localiser sous le même canal (config épinglée, adhésion).
Charger les derniers messages d'un canal. Juste la clé de partition, du plus récent au plus ancien :
KeyConditionExpression: ChannelRef = :ch
ExpressionAttributeValues: { ":ch": "CH#general" }
ScanIndexForward: falseScanIndexForward: false parcourt la collection triée à l'envers — le moyen bon marché
d'obtenir « le plus récent d'abord » sans trier côté client.
Un jour précis avec begins_with. Parce que l'horodatage est la clé de tri et
qu'il est stocké comme texte, un préfixe de date est une tranche nette :
KeyConditionExpression ChannelRef = :ch AND begins_with(PostedAt, :day)
:ch "CH#general"
:day "MSG#2026-06-23"
Ça lit chaque message du 2026-06-23 et rien d'autre — DynamoDB se positionne sur le préfixe et s'arrête quand il en sort. Ça ne marche que parce que le préfixe est un vrai ancrage à gauche d'une chaîne triée par octets.
Une fenêtre précise avec BETWEEN. Pour « les messages pendant l'heure de 14:00 »,
une plage inclusive bat un préfixe :
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 est inclusif sur les deux bornes, donc choisis tes extrémités délibérément —
un décalage d'un cran ici fait silencieusement tomber ou doubler un message de bordure.
Tu peux assembler et copier n'importe laquelle de ces expressions, avec la map
ExpressionAttributeValues remplie pour toi, dans le
DynamoDB expression builder — pratique pour
réussir la syntaxe du begins_with et du BETWEEN du premier coup.
Vois-le dans DynoTable
Lance la même condition de clé contre une vraie partition de canal et regarde la capacité consommée se mettre à jour en direct, pour confirmer que tu lis une tranche — pas toute la collection.
Le piège : confondre une condition de clé avec un filtre
L'erreur coûteuse est de sortir FilterExpression pour faire le travail d'une clé.
KeyConditionExpression: ChannelRef = :ch
FilterExpression: begins_with(PostedAt, :day)Ça semble équivalent à la condition de clé begins_with ci-dessus et renvoie les
mêmes lignes — mais ça lit toute la partition du canal d'abord, puis jette tout ce
qui est hors du jour. Tu es facturé pour la lecture complète.
Les filtres ne réduisent jamais le coût de lecture. Ils s'exécutent après que DynamoDB
a mesuré les items, la même arme à fragmentation qu'un Scan
filtré. Si un prédicat peut aller dans la condition de clé, c'est là qu'il appartient.
Le correctif est en amont : si un motif d'accès ne peut pas s'exprimer comme une égalité de PK plus une plage de clé de tri, c'est un signal de modélisation. Soit remodèle la clé de tri, soit ajoute un index clé pour le motif — vois GSI vs LSI et single-table design pour savoir comment disposer les clés.
Pièges et étapes suivantes
- La clé de partition est toujours
=. Pas de plages, jamais. Si tu as besoin d'une plage à travers les partitions, tu as dépassé un seulQuery. - Une condition de clé de tri par requête. Tu ne peux pas faire un
ANDde deux prédicats de clé de tri ; choisisBETWEENoubegins_with, pas les deux. - Les mots réservés ont besoin d'alias. Une clé nommée
TimestampouNamedoit utiliserExpressionAttributeNames(#ts), ou la requête échoue. (AWS : reserved words) BETWEENest inclusif. Les deux extrémités sont matchées — conçois tes bornes en conséquence.
Rédige tes conditions de clé dans l'expression builder, puis essaie DynoTable pour les exécuter contre tes propres tables et regarder la capacité qu'elles consomment réellement.