Bean & Bark: your first real query
Fourth day on the job. The whole store — 240,000 orders — lives in one DynamoDB table called BeanAndBark. There is no "revenue" button and no "find Dana" button. There is a query box, a founder who needs an answer, and eighteen minutes. This is where you learn the one distinction DynamoDB is built around: a Query that touches three items, versus a Scan that reads — and bills you for — all 240,000.
- Tell a cheap Query from a full-table Scan — and read which one you got before you run it
- See why what you read (and pay for) is not the same as what you asked for
- Pull every order for one customer in a single read, using its partition key
Your first instinct is a trap
You know Dana's name, so you ask for it by name. It reads like plain English and it returns exactly the right orders — which is precisely why it's dangerous. CustomerName isn't a key, so DynamoDB has no door to walk through: it reads every item in the table and throws almost all of them away. That's a Scan.
-- Your instinct: you know her name, so ask for it.SELECT OrderId, Placed, Status, TotalFROM "BeanAndBark"WHERE CustomerName = 'Dana Okafor' -- a plain attribute → Scan Before you run it — a guess. Of the 240,000 items, how many does DynamoDB read to hand back Dana's three orders? Flip between the two variants below and watch the "Executes as" strip: the first asks by name, the second asks by key. Same three orders come back. The bill does not.
Read the two footers. Same three orders, same answer for Nadia — but the Scan read ~240,000 items to find them (< 0.01% of what it touched was useful) and the Query read exactly 3 (100%). What DynamoDB reads is what you pay for; what it returns is only what you asked for. The whole craft is closing that gap — and a single partition key equality closes it completely.
- A partition key equality is the one thing that turns a read into a cheap Query; a plain attribute like
CustomerNameforces a full Scan. - Read ≠ returned. You pay for every item DynamoDB reads, not the rows it hands back — the "Executes as" strip shows the gap before you run.
- One partition key gives you a customer's whole collection of orders in a single, cheap read.
BeanAndBark (keys pk, sk). Which WHERE is a cheap Query?SELECT * FROM "BeanAndBark" WHERE CustomerName = 'Dana Okafor'. Rewrite it to read only Dana's partition.CUSTOMER#c-014. Swap the name filter for a pk equality.Show solution
pk = 'CUSTOMER#c-014' is the key condition (a Query), and begins_with(sk, 'ORDER#') keeps it to orders — one partition, nothing wasted.SELECT OrderId, Placed, Status, TotalFROM "BeanAndBark"WHERE pk = 'CUSTOMER#c-014' AND begins_with(sk, 'ORDER#') Status is still pending.pk equality stays (it's what keeps this a Query). Add Status as a filter within that partition — it's cheap here because you're only reading Dana's items.Show solution
Status = 'pending' runs against the handful of items in Dana's partition, not the whole table.SELECT OrderId, Placed, Status, TotalFROM "BeanAndBark"WHERE pk = 'CUSTOMER#c-014' AND begins_with(sk, 'ORDER#') AND Status = 'pending'