Expressions de projection DynamoDB
Une expression de projection est le SELECT col1, col2 de DynamoDB : une
liste de noms d' séparés par des virgules qui indique à GetItem, Query ou Scan
de ne renvoyer que ces attributs au lieu de l'item entier.
Les expressions de projection DynamoDB réduisent-elles le coût de lecture ?
Non. Une ProjectionExpression réduit la charge utile de la réponse, pas la capacité de lecture qui t'est facturée. DynamoDB lit l'item complet depuis le stockage, compte la sur sa taille sur disque, puis écarte les attributs que tu n'as pas nommés à la sortie. Pour vraiment réduire le coût de lecture, utilise plutôt un couvrant.
- Elle réduit la charge utile, pas le coût de lecture. DynamoDB lit (et facture) l'item
complet depuis le stockage, puis écarte les attributs que tu n'as pas nommés à la
sortie.
ProjectionExpressionest une optimisation réseau, pas une optimisation de capacité. - C'est ainsi que tu récupères un sous-ensemble public. Nomme les quelques attributs qu'un appelant est autorisé à voir ; le reste ne quitte jamais la table.
- Utilise des placeholders
#namepour tout ce qui pourrait être réservé. Les noms d'attributs bruts dans l'expression entrent en collision avec les quelque 570 mots réservés de DynamoDB et font échouer la requête. - Pour de vraies économies de lecture, utilise plutôt un index couvrant. Un qui ne projette que les colonnes dont tu as besoin est lu à sa propre taille (plus petite).
Ce qu'elle économise réellement
Quand tu viens du SQL, tu supposerais que SELECT a, b scanne moins que SELECT *. Dans
DynamoDB cette intuition est fausse. L'unité de capacité
d'une lecture est calculée à partir de la taille de l'item sur disque, arrondie au 4 KB
supérieur — avant que la projection ne soit appliquée. AWS est explicite : une ProjectionExpression
ne change pas la capacité de lecture qu'une requête consomme.1
Donc une projection t'économise deux choses, réelles toutes les deux mais toutes deux en aval de la lecture :
- Des octets sur le réseau. Un item de 6 KB renvoyé sous forme de deux petits attributs est une
réponse minuscule. Sur un
Queryqui renvoie des centaines d'items, ça s'accumule vite. - Du travail côté client. Moins à désérialiser, moins à garder en mémoire, moins à fuir dans un log ou une réponse d'API par accident.
Ce qu'elle n'économise pas, c'est la RCU. C'est le piège : les gens se tournent vers une projection pour réduire leur facture, ne voient aucun changement, et concluent que DynamoDB est cassé. Il ne l'est pas — tu as mesuré le mauvais levier.
Projeter un profil utilisateur public
Disons que tu gères un annuaire d'utilisateurs. Chaque profil est un item, avec une clé qui te permet de récupérer une personne par pseudo :
PK = "PROFILE#ada" (partition key)
SK = "PROFILE#ada" (sort key — single-item collection)
L'item est volumineux. Il porte le visage public du compte plus une pile d'attributs privés et opérationnels :
{
"PK": "PROFILE#ada",
"SK": "PROFILE#ada",
"displayName": "Ada L.",
"avatarUrl": "https://cdn.example.com/u/ada.png",
"bio": "Builds things.",
"emailAddress": "ada@example.com",
"passwordResetToken": "…",
"billingCustomerId": "cus_…",
"lastLoginIp": "…",
"internalRiskScore": 0.02
}Une carte de profil public a besoin de trois champs. Récupérer l'item entier signifie que
emailAddress, lastLoginIp et internalRiskScore voyagent vers un contexte qui
ne devrait jamais les voir. Ne nomme que le sous-ensemble public :
GetItem PK = "PROFILE#ada" SK = "PROFILE#ada"
ProjectionExpression: displayName, avatarUrl, bio
La réponse porte trois attributs. Les privés restent dans la table — pas filtrés par ton application après arrivée, mais jamais sérialisés dans la réponse du tout. C'est le gain de sécurité, et c'est celui qui est difficile à annuler une fois qu'un secret a déjà franchi une frontière.
Tu peux assembler et copier cette requête exacte — noms, placeholders et l'appel
SDK — dans le
générateur d'expressions DynamoDB, qui émet
la ProjectionExpression et la table ExpressionAttributeNames pour toi.
Ajoute ou retire des champs dans le préréglage ci-dessous pour regarder la ProjectionExpression
changer — seuls les attributs listés reviennent :
Échapper les mots réservés avec des placeholders #
Voici où une projection propre explose. DynamoDB réserve une longue liste de
mots — name, status, comment, size, timestamp, et des centaines d'autres.2
Si un attribut que tu projettes est l'un d'eux, le nom brut dans l'expression
est rejeté.
Supposons que le profil ait aussi un attribut status ("active", "suspended").
Ceci échoue :
ProjectionExpression displayName, status
status est réservé. Le correctif est un nom d'attribut d'expression — un
placeholder préfixé par # mappé au vrai nom :
ProjectionExpression displayName, #s
ExpressionAttributeNames { "#s": "status" }
Le même mécanisme s'étend aux attributs imbriqués. Pour extraire un seul champ d'une map, ou un élément d'une liste, utilise la syntaxe de chemin de document — et mets un placeholder sur chaque segment, puisque n'importe lequel d'entre eux pourrait être réservé :
ProjectionExpression #addr.#city, tags[0]
ExpressionAttributeNames { "#addr": "address", "#city": "city" }
Une règle pratique : mets un placeholder sur tout. Tu n'as jamais à te rappeler lequel des
quelque 570 mots réservés tu es en train de fouler, et l'expression se lit de la même façon dans les deux
cas. Et si tu préfères savoir quels noms posent réellement problème, colle-les dans le
vérificateur de mots réservés — il signale
les collisions et émet la map d'alias ExpressionAttributeNames.
Quand un index couvrant bat une projection
Si tu as vraiment besoin de réduire le coût de lecture — pas juste la charge utile — le levier est un
index secondaire global qui ne projette que les attributs que tu lis. Un GSI est une
copie séparée des données ; tu choisis KEYS_ONLY, INCLUDE ou ALL pour sa
projection.3 Un index KEYS_ONLY ou avec un INCLUDE étroit est physiquement
plus petit par item, donc un Query contre lui est compté à cette taille plus petite.
C'est un index couvrant : la requête est entièrement répondue depuis l'index, sans retour à la table de base. Utilise-le quand un mode de lecture fréquent n'a jamais besoin que de quelques attributs de gros items.
ProjectionExpression | GSI couvrant | |
|---|---|---|
| Réduit la charge utile | Oui | Oui |
| Réduit le coût de lecture | Non | Oui — lu à la taille de l'index |
| Stockage supplémentaire | Aucun | Une seconde copie des champs projetés |
| Coût d'écriture supplémentaire | Aucun | Les écritures se propagent à l'index |
| Idéal pour | Cacher des champs privés ; petits gains | Lectures fréquentes de quelques champs d'items volumineux |
Le compromis est honnête : l'index te coûte du stockage et de la capacité d'écriture pour économiser
de la capacité de lecture. Ça vaut le coup pour une lecture fréquente d'une fine tranche d'un item lourd ;
pas pour rogner un GetItem ponctuel. Voir
GSI vs LSI pour choisir le type d'index, et
quand une lecture de GSI peut être obsolète avant
d'en mettre un sur le chemin critique.
Pièges et étapes suivantes
- Ne t'attends pas à une facture plus petite. Une projection seule ne change jamais la RCU. Si le chiffre n'a pas bougé, c'est le comportement documenté, pas un bug.
- Mets un placeholder sur les mots réservés. Un
nameoustatusnu dans l'expression fait échouer la requête — mappe-le avec#. - Inclus toujours les attributs de clé — ils ajoutent une charge utile négligeable et te permettent de paginer ou de récupérer à nouveau l'item.
- Tourne-toi vers un index couvrant seulement quand un mode fréquent lit quelques champs de gros items ; pèse d'abord le coût en écriture/stockage.
Construis la ProjectionExpression et sa table de noms d'attributs dans le
générateur d'expressions, et
essaie DynoTable pour exécuter ces projections contre tes propres tables et
regarder la réponse rétrécir.
- Guide du développeur AWS DynamoDB, Using projection expressions in DynamoDB — la capacité de lecture se calcule sur la taille de l'élément, avant toute application d'une
ProjectionExpression. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html ↩ - Guide du développeur AWS DynamoDB, Reserved Words in DynamoDB. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html ↩
- Guide du développeur AWS DynamoDB, Attribute Projections (
KEYS_ONLY/INCLUDE/ALL). https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html ↩