DynamoDB-Projection-Expressions
Eine Projection Expression ist das SELECT col1, col2 von DynamoDB: eine
kommaseparierte Liste von namen, die GetItem, Query oder
Scan sagt, nur diese Attribute statt des ganzen Items zurückzugeben.
Reduzieren DynamoDB-Projection-Expressions Read-Kosten?
Nein. Eine ProjectionExpression trimmt das Response-Payload, nicht die Read
Capacity, die abgerechnet wird. DynamoDB liest das volle Item aus Storage, metert
die anhand seiner On-Disk-Größe und droppt dann die Attribute,
die du nicht genannt hast, auf dem Weg raus. Um Read-Kosten wirklich zu senken,
nutze stattdessen einen covering .
- Sie trimmt das Payload, nicht die Read-Kosten. DynamoDB liest (und rechnet)
das volle Item aus Storage und droppt dann die Attribute, die du nicht genannt
hast, auf dem Weg raus.
ProjectionExpressionist eine Network-Optimierung, keine Capacity-eine. - So holst du eine public Subset. Nenne die wenigen Attribute, die ein Caller sehen darf; der Rest verlässt die Tabelle nie.
- Nutze
#name-Placeholder für alles, was reserved sein könnte. Plaine Attributnamen in der Expression kollidieren mit DynamoDBs ~570 Reserved Words und failen den Request. - Für echte Read-Ersparnis nutze stattdessen einen Covering Index. Ein , der nur die Columns projeziert, die du brauchst, wird bei seiner eigenen (kleineren) Größe gelesen.
Was sie wirklich spart
Aus SQL würdest du annehmen, SELECT a, b scannt weniger als SELECT *. In
DynamoDB ist diese Intuition falsch. Die
Capacity Unit für einen Read wird aus der
Größe des Items on Disk berechnet, aufgerundet auf die nächsten 4 KB — bevor
die Projektion angewandt wird. AWS ist explizit: eine ProjectionExpression
ändert nicht die Read Capacity, die ein Request verbraucht.1
Eine Projektion spart dir also zwei Dinge, beide real, aber beide downstream des Reads:
- Bytes über die Leitung. Ein 6-KB-Item, zurückgegeben als zwei kleine
Attribute, ist eine winzige Response. Auf einer
Query, die Hunderte Items zurückgibt, summiert sich das schnell. - Clientseitige Arbeit. Weniger zu deserialisieren, weniger im Memory zu halten, weniger versehentlich in ein Log oder eine API-Response zu leaken.
Was sie nicht spart, ist die RCU. Das ist der Fallstrick: Leute greifen nach einer Projektion, um die Rechnung zu senken, sehen keine Änderung und schließen, DynamoDB sei broken. Ist es nicht — du hast den falschen Hebel gemessen.
Ein öffentliches User-Profil projeizieren
Angenommen, du betreibst ein User Directory. Jedes Profil ist ein Item, so gekeyed, dass du eine Person per Handle fetchen kannst:
PK = "PROFILE#ada" (partition key)
SK = "PROFILE#ada" (sort key — single-item collection)
Das Item ist fett. Es trägt das öffentliche Gesicht des Accounts plus einen Haufen privater und operationaler Attribute:
{
"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
}Eine öffentliche Profilkarte braucht drei Felder. Das ganze Item zu fetchen heißt,
emailAddress, lastLoginIp und internalRiskScore reisen in einen Kontext, der
sie nie sehen sollte. Nenne nur die public Subset:
GetItem PK = "PROFILE#ada" SK = "PROFILE#ada"
ProjectionExpression: displayName, avatarUrl, bio
Die Response trägt drei Attribute. Die privaten bleiben in der Tabelle — nicht von deiner App nach Ankunft herausgefiltert, sondern nie überhaupt in die Response serialisiert. Das ist der Security-Win, und er ist schwer rückgängig zu machen, sobald ein Secret eine Boundary gekreuzt hat.
Du kannst genau diesen Request — Names, Placeholder und den SDK-Call — im
DynamoDB Expression Builder zusammenbauen und
kopieren, der die ProjectionExpression und ExpressionAttributeNames-Map für
dich emittiert.
Füge Felder im Preset unten hinzu oder entferne sie, um die ProjectionExpression
zu beobachten — nur die gelisteten Attribute kommen zurück:
Reserved Words mit #-Placeholdern escapen
Eine saubere Projektion explodiert an Reserved Words. DynamoDB reserviert eine
lange Liste — name, status, comment, size, timestamp und Hunderte
mehr.2 Ist ein Attribut, das du projezierst, eines davon, wird der rohe
Name in der Expression rejected.
Angenommen, das Profil hat auch ein status-Attribut ("active", "suspended").
Das failt:
ProjectionExpression displayName, status
status ist reserved. Der Fix ist ein Expression Attribute Name — ein #-
prefixed Placeholder, gemappt auf den echten Namen:
ProjectionExpression displayName, #s
ExpressionAttributeNames { "#s": "status" }
Derselbe Mechanismus greift in nested Attribute. Um ein einzelnes Feld aus einer Map oder ein Element einer List zu ziehen, nutze Document-Path-Syntax — und placeholder jedes Segment, denn jedes könnte reserved sein:
ProjectionExpression #addr.#city, tags[0]
ExpressionAttributeNames { "#addr": "address", "#city": "city" }
Eine praktische Regel: placeholder alles. Du musst nie merken, auf welchem der
~570 Reserved Words du stehst, und die Expression liest sich so oder so gleich.
Und wenn du lieber wissen willst, welche Namen wirklich das Problem sind, paste
sie in den Reserved-Words Checker — er
flaggt die Kollisionen und emittiert die ExpressionAttributeNames-Alias-Map.
Wann ein Covering Index eine Projektion schlägt
Brauchst du wirklich, Read-Kosten zu senken — nicht nur Payload — ist der Hebel
ein Global Secondary Index, der nur die Attribute projeziert, die du liest.
Ein GSI ist eine separate Kopie der Daten; du wählst KEYS_ONLY, INCLUDE oder
ALL für seine Projektion.3 Ein KEYS_ONLY- oder enger INCLUDE-Index
ist physisch kleiner pro Item, also wird eine Query dagegen bei dieser kleineren
Größe gemetered.
Das ist ein Covering Index: die Query wird vollständig aus dem Index beantwortet, kein Trip zurück zur Base Table. Nutze ihn, wenn ein hot Read Pattern nur je ein paar Attribute aus großen Items braucht.
ProjectionExpression | Covering GSI | |
|---|---|---|
| Kürzt Payload | Ja | Ja |
| Kürzt Read-Kosten | Nein | Ja — Read bei der Größe des Index |
| Extra Storage | Keiner | Eine zweite Kopie der projezierten Felder |
| Extra Write-Kosten | Keine | Writes propagieren zum Index |
| Am besten für | Private Felder verstecken; kleine Wins | Hot Reads weniger Felder aus großen Items |
Der Index kostet dich Storage und Write Capacity, um Read Capacity zu sparen.
Wert für einen häufigen Read eines dünnen Slice aus einem schweren Item; nicht
wert, um ein One-off-GetItem zu shaven. Siehe
GSI vs LSI für den Index-Typ, und
wann ein GSI-Read stale sein kann,
bevor du einen auf den Hot Path legst.
Fallstricke und nächste Schritte
- Erwarte keine kleinere Rechnung. Eine Projektion allein ändert nie RCU. Wenn die Zahl sich nicht bewegt hat, ist das dokumentiertes Verhalten, kein Bug.
- Placeholder Reserved Words. Ein nacktes
nameoderstatusin der Expression failt den Request —#-mappe es. - Schließe immer die Key-Attribute ein — sie addieren vernachlässigbares Payload und lassen dich das Item pagen oder re-fetchen.
- Greif zu einem Covering Index nur, wenn ein hot Pattern wenige Felder aus großen Items liest; wäge zuerst Write-/Storage-Kosten.
Baue die ProjectionExpression und ihre Attribute-Name-Map im
Expression Builder, und
probier DynoTable, um diese Projektionen gegen deine eigenen Tabellen
zu fahren und die Response schrumpfen zu sehen.
- AWS DynamoDB Developer Guide, Using projection expressions in DynamoDB — die Read Capacity richtet sich nach der Item-Größe, bevor irgendeine
ProjectionExpressionangewendet wird. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html ↩ - AWS DynamoDB Developer Guide, Reserved Words in DynamoDB. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html ↩
- AWS DynamoDB Developer Guide, Attribute Projections (
KEYS_ONLY/INCLUDE/ALL). https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html ↩