AWS Cloud Architect & Developer · AWS Cloud Architecture
DynamoDB NoSQL
Fully managed key value and document NoSQL database with single digit millisecond latency.
Seven concepts on DynamoDB for the Solutions Architect exam — primary-key design, capacity modes, RCU/WCU sizing, Query versus Scan, secondary indexes, change streams, and DAX. Every stem here is really asking which access pattern the table keys support and how much capacity that pattern consumes.
- AWS Cloud Architect & Developer
- Medium level
- 7 concepts
- 5 practice questions
1Primary keys and partition design
Every DynamoDB item is addressed by a primary key. A simple key is a partition key alone; a composite key adds a sort key so multiple items can share one partition key and be ordered or ranged within it. The partition key is not just an identifier — it is the hash input that decides which physical partition stores the item, so its cardinality and distribution shape throughput.
A low-cardinality partition key — status=active on a table with millions of rows — concentrates writes and reads on one partition and creates a hot partition that throttles even when the table's total capacity looks generous. High-cardinality keys (userId, orderId, a composite of tenantId plus shard suffix) spread load. Concatenating attributes is a common exam trick to turn a skewed attribute into many distinct partition keys.
Figure. Partition key chooses the shard; sort key orders items inside that partition for Query ranges.
How keys drive access
- Name the partition keyThis is the attribute you must supply in every efficient Query — it alone determines which partition DynamoDB reads.
- Add a sort key when neededComposite keys let you store many items under one partition key and query a range (time-ordered sessions per user, line items per order).
- Check cardinalityIf one value could dominate traffic, redesign the partition key or add a random suffix to spread writes.
| Key shape | What it stores | Typical query |
|---|---|---|
| Partition key only | One item per partition-key value | GetItem or Query on that exact value |
| Partition + sort key | Many items sharing a partition key | Query with partition key plus sort-key condition (between, begins_with) |
A table stores every order with partition key status (pending, shipped, delivered). Write traffic spikes during a sale. What is the most likely bottleneck?
- The 400 KB item size limit
- Hot partitions because status has very low cardinality
- Missing a Global Secondary Index
status has only a handful of values, so nearly every write hits the same few partitions regardless of total table capacity. A GSI does not fix a badly chosen table partition key — you redesign the key (orderId, customerId, or a composite) so writes spread.
2Provisioned versus On-Demand capacity
Provisioned mode sets explicit read and write capacity units (RCU/WCU) with optional Application Auto Scaling to track load. You pay for the capacity you reserve whether or not every unit is used, which rewards steady, forecastable traffic.
On-Demand mode bills per request and scales without you pre-sizing RCU/WCU. Instant headroom covers bursts near a recent peak (classically about double that peak); larger brand-new peaks keep scaling as DynamoDB adds capacity. That still makes On-Demand the default exam answer for spiky or unknown workloads (a game launch, a flash sale) — including stems that quote a 10× launch multiplier you could not have provisioned in advance. You can switch between modes once every 24 hours, so launching On-Demand and moving to Provisioned with auto scaling after traffic stabilises is a valid cost-optimisation path.
Figure. Provisioned caps and prices reserved throughput; on-demand bills per request with automatic scaling.
Which mode the stem wants
- Traffic unknown or spiky?On-Demand — no capacity planning, pay per request; do not reject it because a stem says 10×.
- Steady, predictable load?Provisioned with auto scaling — cheaper at sustained utilisation when you can forecast RCU/WCU.
- After launch stabilisesReassess: switch to Provisioned (once per 24 h) if the peak is now predictable.
| Trait | Provisioned | On-Demand |
|---|---|---|
| Billing | Reserved RCU/WCU (used or not) | Per-request |
| Scaling | Manual set + optional auto scaling | No pre-size; auto-scales with traffic |
| Peak headroom | Must provision enough RCU/WCU | ≈2× recent peak instantly, then continues for larger new peaks |
| Best when | Steady, forecastable traffic | Spiky or unknown traffic |
A new game's leaderboard may see 10× traffic at launch with no reliable forecast. Which capacity mode do you choose first?
- Provisioned with a fixed RCU/WCU estimate
- On-Demand
- Provisioned with auto scaling set to minimum capacity
Unknown spike magnitude means you cannot size Provisioned capacity correctly without over- or under-provisioning. On-Demand is still correct for a 10× launch: the ≈2× figure is instant headroom near a *recent* peak, not a hard ceiling that flips the answer to Provisioned. After traffic stabilises you can switch to Provisioned with auto scaling to save cost.
3RCU and WCU sizing
Read capacity is measured in RCUs. One RCU supports one strongly consistent read per second for an item up to 4 KB, or two eventually consistent reads per second for items up to 4 KB each. Write capacity is simpler: one WCU is one write per second for an item up to 1 KB. DynamoDB always rounds up to the next 4 KB boundary for reads and the next 1 KB boundary for writes.
Item size matters twice: larger items consume more units per access, and a single item cannot exceed 400 KB including all attributes. Exam stems often pair a stated item size with a read consistency choice — compute RCUs with the 4 KB chunk rule, then halve (rounding up) for eventually consistent reads.
Figure. RCU/WCU round item size to 4KB/1KB blocks — oversized items multiply write units fast.
How to size a request
- Measure item sizeSum all attribute bytes; confirm it is under the 400 KB per-item limit.
- Reads: divide by 4 KB, round upThat count is RCUs for one strongly consistent read per second.
- Eventually consistent readsHalf the strong RCU count, rounded up — two eventual reads of 4 KB each share one RCU.
- Writes: divide by 1 KB, round upThat count is WCUs for one write per second.
Sizing reads and writes on real item sizes
A leaderboard item is 10 KB. How many RCUs does one strongly consistent read per second require, and how many for eventually consistent? A session record is 2.5 KB — how many WCUs per write per second?
- Strong read: ceil(10 KB ÷ 4 KB)3 RCU
- Eventual read: ceil(3 ÷ 2)2 RCU
- Write: ceil(2.5 KB ÷ 1 KB)3 WCU
Pro tip. Do not halve the item size before dividing — halve the RCU count after rounding up the strong read. A 10 KB eventual read is 2 RCU, not 1.
An item is 6 KB. How many RCUs does one strongly consistent read per second consume?
- 1 RCU
- 2 RCU
- 3 RCU
ceil(6 ÷ 4) = 2 RCU. Answering 1 RCU assumes the whole item fits in 4 KB; answering 3 RCU divides 6 by 2 KB instead of the 4 KB read chunk.
4Query, Scan, and TTL
Query requires a partition key (and optionally a sort-key condition) and reads only the matching item collection — this is the efficient access path every well-modelled table should use. Scan reads every item in the table (or index) and consumes capacity proportional to table size, regardless of how few rows match a filter. The exam trap is reaching for Scan when the fix is a better key or a GSI.
Time to Live (TTL) lets DynamoDB delete expired items automatically based on a numeric epoch attribute (expiresAt). TTL deletes are free and need no application cron — enable TTL on the attribute and DynamoDB removes stale rows in the background.
Figure. Query names a partition key and optional sort-key condition, so it touches one item collection. Scan walks the whole table (or index) and burns capacity proportional to size. TTL deletes expire items without changing that access choice.
Modelling a sessions table
- Partition + sort for the main pathuserId as partition key and sessionTimestamp as sort key — Query returns a user's sessions in time order.
- Enable TTLSet expiresAt as the TTL attribute so stale sessions delete automatically at no write cost.
- Lookup by sessionId aloneThat is a different partition key — add a GSI on sessionId (see the GSI concept).
- Never Scan for routine lookupsScan is the fallback when no key or index supports the access pattern.
You must fetch all sessions for userId u-42 ordered by time. Which operation and key?
- Scan with filter userId = u-42
- Query on partition key userId = u-42
- GetItem on sessionTimestamp alone
userId is the partition key, so Query on that value reads only that user's item collection efficiently. Scan reads the whole table; GetItem needs the full primary key including the sort key.
5Global versus Local Secondary Index
A secondary index lets you query on attributes beyond the table's primary key. A Global Secondary Index (GSI) has its own partition key and optional sort key — you can query any attribute pattern you project, provision separate capacity, and add or drop GSIs after the table exists. A Local Secondary Index (LSI) keeps the table's partition key but swaps in an alternate sort key; it must be defined at table creation, shares the table's throughput, and all items with the same partition key share a 10 GB item-collection limit. If the exam stem needs to look up rows by an attribute that is not the primary key, the answer is almost always a GSI, not an LSI.
Figure. An LSI must reuse the table's partition key and can only be created with the table. A GSI may choose a new partition key and can be added later — that is the fork the comparison table encodes.
Which index the stem wants
- Same partition key, new sort order?LSI — only if the table was created with that LSI and you stay within the 10 GB per-partition-key collection.
- Different partition key or post-launch need?GSI — own key schema, own capacity, add anytime.
- Query a non-key attributeGSI with that attribute as the index key (or projected for filter). Scan is the expensive fallback.
| Trait | Global Secondary Index (GSI) | Local Secondary Index (LSI) |
|---|---|---|
| Key schema | New partition key (+ optional sort key) | Same partition key, alternate sort key |
| When you can add it | Anytime after table creation | Only at table creation |
| Capacity | Separate RCU/WCU (or on-demand) | Shares table capacity |
| Per-partition limit | No 10 GB item-collection cap | 10 GB item-collection limit per partition key |
| Typical exam use | Query/filter on a non-key attribute | Alternate sort order within one partition key |
A sessions table uses userId as partition key and sessionTimestamp as sort key. After launch you must look up any session by sessionId alone. What do you add?
- A Local Secondary Index on sessionId
- A Global Secondary Index with sessionId as the partition key
- A table Scan filtered on sessionId
sessionId is not the table's partition key, and the table already exists — LSI cannot be added now and would not change the partition key anyway. A GSI on sessionId gives an efficient Query path; Scan works but burns capacity across every item.
6DynamoDB Streams
DynamoDB Streams captures item-level change events — insert, modify, remove — and retains them for 24 hours. Each stream record includes the keys and, depending on stream view type, the new image, old image, or both. Streams are ordered per partition key, so related changes on the same key arrive in sequence.
The standard exam pattern is Streams plus Lambda: enable a stream on the table, attach a Lambda event source mapping, and react to changes without polling. Use this for replication to another store, aggregating counters, sending notifications, or any event-driven workflow triggered by writes.
Figure. Item changes flow table → Stream (24 h retention) → Lambda via an event source mapping.
Event-driven processing path
- Enable the streamTurn on DynamoDB Streams on the table and pick the view type (keys only, new image, old image, or both).
- Attach LambdaCreate an event source mapping from the stream to a Lambda function — no polling loop required.
- Process within 24 hoursRecords expire after 24 h; design idempotent handlers in case of retries.
Every new order row must trigger a fulfillment Lambda within seconds. What is the most appropriate integration?
- A cron job that Scans the table every minute
- DynamoDB Streams with a Lambda event source mapping
- CloudWatch Events on a five-minute schedule
Streams push item-level changes to Lambda in near real time. Scanning on a schedule adds latency, wastes RCUs, and can miss the tight timing requirement. CloudWatch schedule polling is the same problem as cron Scan.
7DAX read acceleration
DynamoDB Accelerator (DAX) is an in-memory cache cluster in front of DynamoDB tables. It delivers microsecond read latency for read-heavy workloads where the same items are fetched repeatedly — leaderboards, user profiles, session lookups under load.
DAX is not a replacement for proper key design or GSIs; it accelerates reads that already hit the table efficiently. Writes still go to DynamoDB; DAX handles cache invalidation. Add DAX when the stem emphasises read latency at scale, not when the problem is a missing access pattern.
Figure. DAX is a write-through cache in front of DynamoDB for microsecond reads of hot keys.
When DAX fits
- Read-heavy and repetitive?Same keys fetched many times per second — leaderboard scores, hot product pages.
- Microsecond latency required?DAX sits closer than repeated DynamoDB reads even at single-digit millisecond table latency.
- Access pattern already correct?Fix keys and indexes first; DAX caches successful reads, it does not invent a query path.
After launch, leaderboard reads dominate and must stay in the microsecond range under 10× load. Keys and GSIs are already correct. What do you add?
- Switch the table to Scan for simpler code
- Add a DAX cluster in front of the table
- Enable DynamoDB Streams
DAX caches hot reads with microsecond latency. Streams trigger downstream processing, not read acceleration. Scan would make latency and cost worse.
Notes
- Primary Keys: A partition key alone (simple key) or a partition key plus sort key (composite key) uniquely identifies items and determines data distribution across partitions.
- Capacity Modes: Provisioned mode sets read/write capacity units (with optional auto scaling); On-Demand mode auto-scales instantly and bills per request for unpredictable workloads.
- Secondary Indexes: A Global Secondary Index (GSI) allows queries on non-key attributes with its own capacity, while a Local Secondary Index (LSI) shares the partition key but uses an alternate sort key.
- DynamoDB Streams: Capture item-level change events (insert/modify/remove) for 24 hours, commonly consumed by Lambda for replication or event-driven processing.
- DAX: DynamoDB Accelerator is an in-memory cache delivering microsecond read latency for read-heavy, cache-friendly workloads.
Formulas
- Read capacity: 1 RCU = one strongly consistent read/sec of up to 4 KB, or two eventually consistent reads/sec.
- Write capacity: 1 WCU = one write/sec of up to 1 KB.
- Item size limit: a single item (all attributes) cannot exceed 400 KB.
- LSI constraint: must be created at table creation, shares the 10 GB per-partition-key item-collection limit; GSIs can be added anytime.
- On-Demand throughput: instantly serves up to double the previous peak traffic without pre-provisioning.
Exam traps & shortcuts
- If a query needs to filter on an attribute that is not the primary key, the answer is almost always a Global Secondary Index.
- For spiky or unknown traffic, choose On-Demand; for steady, predictable load where cost matters, choose Provisioned with auto scaling.
- To trigger downstream processing on data changes, enable DynamoDB Streams with a Lambda trigger rather than polling the table.
- Choose a high-cardinality partition key to avoid hot partitions; concatenating attributes can spread load evenly.
Reference tables
| Rule | Value |
|---|---|
| Strong read throughput | 1 RCU = one read/sec of up to 4 KB |
| Eventual read throughput | 1 RCU = two reads/sec of up to 4 KB each |
| Write throughput | 1 WCU = one write/sec of up to 1 KB |
| Maximum item size | 400 KB (all attributes combined) |
| LSI item collection | 10 GB per partition key value |
| On-Demand peak | ≈2× recent peak instantly; larger new peaks continue scaling |
| Capacity mode switch | Once every 24 hours |
Recap
DynamoDB exam traps cluster around access patterns and capacity — not around memorising service names.
- Non-key lookup
- Filter on an attribute that is not the primary key → GSI, not LSI or Scan.
- Spiky traffic
- Unknown or launch-day spikes → On-Demand first; Provisioned with auto scaling once load is predictable.
- Hot partition
- Low-cardinality partition key → redesign the key or shard; more table RCU does not fix skew.
- Query vs Scan
- Always prefer Query on a partition key; Scan is the expensive whole-table fallback.
- Change processing
- React to writes → DynamoDB Streams + Lambda, not polling Scan.
- Read latency at scale
- Correct keys plus read-heavy hot keys → DAX for microsecond cache hits.
- TTL cleanup
- Auto-expire rows → enable TTL on a numeric epoch attribute; deletes are free.
Practise DynamoDB NoSQL
Reading is free and needs no account. Practice, mocks and progress live in the app.
- 5 exam-style questions on this topic, with explanations
- A 5-question practice set that ends the chapter
- Timed mocks scored with the real marking scheme
- Readiness tracked per topic, kept on your device