Access Patterns, Query vs. Scan

2.Design the Questions First

M

In this chapter

We'll see why DynamoDB design starts from the questions an app will actually ask, not the entities — Query stays cheap and partition-scoped, Scan reads the whole table no matter how tight the filter is.

9–11 min

The Problem in Real Life

"Show me mike01's orders" comes back instantly — a Query naming the partition key, exactly like the last chapter's own example. Then Mike asks a different kind of question: "how many orders across the whole store were over $50 this month?"

Sarah runs the closest thing DynamoDB has to "just look through everything" — and watches the consumed capacity jump by an order of magnitude, for a question that, in a relational database, would have just been another WHERE clause.

M

That's a bigger question. Why did it cost that much more to ask?

Mike

Query vs. Scan

Query touches one partition

Requires a partition key value, and only ever reads the partition that key routes to.

Scan touches every partition

Reads the whole table first, then filters — the filter narrows the results, not the work.

Design starts from the question

List the real access patterns first — the table gets shaped to make them cheap Query calls, not the other way around.

No join to fall back on

A relational design can patch a missed access pattern with a JOIN later — DynamoDB has no equivalent safety net.

Access Patterns, Query vs. Scan

Query and Scan look like they do similar things — both return items — but they work in genuinely different ways underneath. Query always requires a partition key value, and only ever reads the one partition that key routes to. Scan reads every item in the table, across every partition, checking each one against whatever filter it's given — the filter happens after the expensive part, not instead of it.

Only mike01's own partition gets touched. Consumed capacity scales with how much data that one customer has — completely unaffected by how many other customers, or how many total orders, GreenMart has.

Query — One Partition, Cheap and Fast
Query("Orders", { customerId: "mike01" })

Every item, in every partition, gets read and checked against total: { $gt: 50 } — the filter narrows the results, not the work. Consumed capacity scales with the entire table's size, not with how many items actually matched.

Scan — Every Partition, Genuinely Expensive
Scan("Orders", { filter: { total: { $gt: 50 } } })

The simulator's own summary line for a Scan says so explicitly — it's not hiding the cost, it's naming it.

This is exactly why DynamoDB design works backward from how a relational schema usually gets built. A relational table gets designed around the entities first — Customers, Orders, Products — and the queries get figured out afterward, because joins can stitch almost anything together later. DynamoDB doesn't offer that safety net. If a real access pattern needs a Scan to answer, it's going to be the expensive operation every single time that question gets asked — not once, during initial design, but on every request, forever.

So the actual design process starts from the other end entirely: list out every real question GreenMart's application is going to ask — "this customer's orders," "orders in this date range for this customer," "is this order still pending" — before deciding on a partition key or a table shape at all. The table gets designed to make those specific, known questions into Query calls. Anything that would need a Scan either gets a different access path (a secondary index, coming up next chapter) or gets accepted as a rare, deliberately-expensive operation, not a routine one.

Key Takeaway

In DynamoDB, you don't start by designing tables. You start by designing the questions your application needs to ask — the table gets built to answer those questions cheaply.

Why This Matters

Every chapter left in this Act assumes this same discipline. Single-table design, secondary indexes, even the capacity and cost chapter later — all of it is really this one idea, applied to a bigger table with more entities and more real access patterns competing for the same partition key.

GreenMart's Orders table now answers its real, known questions cheaply. The next problem is bigger: DynamoDB tables aren't meant to hold just one kind of item, and figuring out how several genuinely different things share one table, on purpose, is exactly where the next chapter goes.

Next