Loading...
Loading...
Fully managed, serverless, key-value NoSQL database with single-digit millisecond performance.
Fully managed key-value & document NoSQL database designed for single-digit millisecond latency at any scale.
DynamoDB groups data into 'Item Collections' based on the Partition Key (PK). A Query specifying a PK routes directly to one partition. A Scan without a PK must search every partition, which is slow and expensive.
Why is adding a Secondary Index (GSI) sometimes necessary if you have a good Partition Key?
You already know from the sharding module how a shard key decides which machine owns each row, and from the denormalization module how duplicating data at write time removes joins at read time. Relational tables are lovely for flexibility: users here, orders there, payments elsewhere, joined at read time. But a dashboard that stitches four tables per viewer becomes a chase across disks as rows grow into billions, with latency that swings wildly. DynamoDB (a managed key-value store that spreads rows by hash across many machines) answers by refusing the join: store one viewer's things together so one lookup returns the whole screen.
Think of a lunchbox packed for your exact order, the one comparison we will use here: the kitchen pre-packs your sandwich, drink, and dessert together instead of making you queue at four counters. In the lab above, load one user's dashboard with scattered tables versus one grouped lookup and watch four disk chases collapse into one, because the packing happened at write time instead of read time.
Four separate disk neighborhoods per viewer, joined in memory on every load.
Single-table design means keeping profile, orders, payments, and addresses as separate rows in the same table, sharing one partition key (the grouping id, here the user id) with different sort keys (the labels that order rows inside the group). The partition key decides which machine owns the group by hashing it. The sort key decides the order on disk, so asking for one group plus a prefix like ORDER returns exactly that slice in one fast read with no join.
| Group id (PK) | Label (SK) | Payload |
|---|---|---|
| USER#123 | PROFILE | { name: "Alice" } |
| USER#123 | ORDER#1001 | { total: 45.00 } |
| USER#123 | ORDER#1002 | { total: 12.50 } |
| USER#123 | PAYMENT#5 | { status: "paid" } |
| USER#999 | PROFILE | { name: "Bob" } |
| USER#999 | ORDER#55 | { total: 9.99 } |
group = USER#123 and the profile, orders, and payment arrive together in one read. No join runs.Hash the group id to a partition (a slice of storage on one machine).
In the lab, look up two groups and confirm they land on different partitions, because the hash of the group, not the label, decides placement.
Labels sort alphabetically, so prefixes select tight ranges.
A hot partition means one group receiving far more traffic than its machine can serve. Each partition sustains roughly low thousands of reads per second, so 100,000 reads per second aimed at USER#1 needs about 100,000 / 3,000 ≈ 33 partitions worth of capacity but owns one. The naive single-group design for a viral account fails exactly here. The fix is spreading heat: suffix the group with a shard number like USER#1#07, or lift counters and leaderboards out of one group entirely. We rejected keeping one giant group for viral keys because no capacity setting rescues a single partition that owns all the heat.
In the lab, skew traffic to one group and watch throttles climb on one partition only, because heat follows the grouping id.
Many distinct grouping ids, called high cardinality, spread load because distinct hashes land on distinct machines.
A GSI (global secondary index, a maintained copy of the table re-grouped by a different id) answers searches like by-email when the main grouping is user id. The store copies writes into the second grouping in the background, so reads by email stay single-lookup fast at the price of extra storage and brief index lag.
Gateways with no stored state receive your request, hash the grouping id, and forward to the owning partition. Any router gives the same answer.
Each write replicates to two more isolated data centers (availability zones) before it counts as durable, so losing one building loses nothing.
Model access patterns first, hashes second, joins never. Do that and the store answers in single milliseconds at any scale. Which of your own queries would force a second access pattern, and would that pattern deserve its own grouping or a secondary index?
Try this in the playground
Open a template and build it yourself — then take a quiz.