The DynamoDB Cost Model: Why SQL Can Hide the Bill
Running real SQL against DynamoDB is powerful — you get JOINs, GROUP BY, and
arbitrary WHERE clauses over a database that natively offers none of them. But SQL
was designed for an engine with a query planner and secondary indexes on every
column, and DynamoDB has neither. A perfectly legal SELECT can compile to a
full-table Scan that reads — and bills you for — every item in the table.
This is the double edge of the SQL abstraction: it makes expensive access patterns look free. This guide explains the cost model underneath, so the convenience never turns into a surprise bill, and shows how DynoTable surfaces the cost before you run the query.
Why does SQL over DynamoDB cost more than it looks?
A relational database can answer WHERE status = 'active' efficiently because it
builds an index for any column you ask about. DynamoDB does not. It answers
efficiently on exactly one thing: the partition key (optionally narrowed by a
sort key or a global secondary index). Anything else is a Scan.
- A partition-key equality is a Query. DynamoDB jumps straight to the items under that key and reads only those. Bounded and cheap.
- Anything else is a Scan + Filter. DynamoDB reads every item in the table,
then applies your
WHEREas aFilterExpression— after the read. You are billed for everything it scanned, not for the handful of rows returned.
That last point is the trap. A WHERE clause looks like it narrows the work. On
a non-key attribute, it only narrows the output — the read cost is already spent.
Query vs Scan: the RCU math
DynamoDB bills reads in read capacity units (RCU):
- 1 RCU = one strongly-consistent read of an item up to 4 KB. Eventually- consistent reads cost half a unit. Reads round up per 4 KB.
- A Query reads only the items under one partition key — cost scales with the matched items, not the table.
- A Scan reads the whole table, 4 KB at a time. A 1 GB table is roughly 262,000 eventually-consistent RCU for a single full pass — every pass, every time.
A FilterExpression does not reduce that number. Filtering happens after the
read, so a filtered Scan costs exactly as much as an unfiltered one. Work out the
real numbers for your data with the item size calculator
and the pricing calculator.
Which SQL constructs quietly turn into Scans?
WHEREwith no partition-key equality → a full Scan with a post-read filter.JOIN→ there is no server-side join in DynamoDB. Each joined table is fetched separately and stitched together client-side — an N+1 access pattern, one request per joined row.COUNT,SUM,GROUP BY, aggregates → no server-side aggregation exists, so every matched item is read. Over a Scan, that means reading the entire table.ORDER BYorDISTINCTon a non-key attribute → sorting and de-duplication happen client-side over whatever was scanned.
None of these are wrong to run — sometimes a Scan is exactly what you want. The point is to know when you are running one.
How do I keep SQL honest about cost?
- Design keys around your access patterns. The cheapest query is the one your key schema already answers. Plan it with the single-table design tool and the query vs scan guide.
- Put a partition-key equality in the
WHEREto get a Query instead of a Scan. - Add a GSI for a second access pattern rather than scanning-and-filtering.
- Read the cost before you run. DynoTable's Workbench compiles your SQL to the
actual DynamoDB operation and shows the plan — Scan vs Query, which index it
uses, the key condition vs the post-scan filter, and an estimated RCU cost — then
flags full scans and N+1 joins inline. It is the
EXPLAINthat DynamoDB never shipped. See also why scans are slow and expensive and on-demand vs provisioned capacity.
Does DynoTable's SQL make the cost problem worse?
No — because it makes the cost visible. The critique of SQL-over-DynamoDB is fair: an abstraction that hides scans lets you foot-gun yourself. DynoTable's answer is not to remove the SQL, but to put a cost X-ray behind it. Every query in the Workbench previews its real DynamoDB shape before it runs, so you keep the ergonomics of SQL and the honesty about RCUs and key design that the native model gives you.
Do I need the AI agent for any of this?
No — the table viewer, the SQL Workbench, and the cost preview all work fully without it. The AI agent is one of DynoTable's headline features — a DynamoDB-native coding agent that writes schema-aware queries, transforms data, and more — and it's there whenever you want it. It runs on your own AWS Bedrock, so you pay AWS directly at cost (no markup), and your data never leaves your account. Turn it on when it helps; the core client is complete either way.
Is my work portable?
Yes. DynoTable speaks standards, not a walled garden: standard SQL, standard AWS credentials and SSO, CSV/JSON export, inferred-schema export to TypeScript, JSON-Schema, or Zod, and an MCP server so your own tools and agents can connect. Your queries, configs, and schemas export cleanly — nothing is locked in.
Try it
Download DynoTable and open the SQL Workbench against your own table — the cost preview shows you what every query really costs before you run it.