PrepZone Logo
PrepZone

DynamoDB Access Patterns

Design tables around queries, capacity units, and why scans are the last resort.

Read these first

Why this matters

  • VaultCommerce order history needs "all orders for user X, newest first" — composite key PK=USER#X, SK=ORDER#timestamp satisfies that in one Query.
  • Table scans read every partition and burn RCUs — acceptable only for small admin exports, never for customer-facing APIs.
  • Hot partition keys (everyone writing PK=FLASH_SALE) throttle the whole shard regardless of table size.
Partition key: USER#42Routes to shard
Items in partition
ORDER#2026-001Sort key
ORDER#2026-002Sort key
PROFILESort key
Partition key routes to a shard. Sort key orders items within that partition.

Design queries first

VaultCommerce access patterns

  • Get order by user + order id — GetItem on PK=USER#42, SK=ORDER#2026-0042.
  • List recent orders for user — Query PK=USER#42, SK begins_with ORDER#, ScanIndexForward=false.
  • Record idempotency token — PutItem with condition attribute_not_exists(PK).
  • Admin export (rare) — Scan with filter (last resort, off-peak only).
Java
import boto3
from boto3.dynamodb.conditions import Key

table = boto3.resource("dynamodb").Table("VaultCommerceOrders")

def recent_orders(user_id: int, limit: int = 20):
    return table.query(
        KeyConditionExpression=Key("PK").eq(f"USER#{user_id}")
        & Key("SK").begins_with("ORDER#"),
        ScanIndexForward=False,
        Limit=limit,
    )["Items"]

Query vs Scan

Java
# Good: single-partition query
table.query(KeyConditionExpression=Key("PK").eq("USER#42"))

# Bad: full table scan (avoid in production APIs)
table.scan(FilterExpression=Attr("status").eq("SHIPPED"))

Queries specify partition key equality and optional sort-key condition — DynamoDB reads only relevant partitions. Scans iterate the entire table (1 MB pages) then apply filters — filters do not reduce RCU cost.

Capacity units

| Mode | When to use | |------|-------------| | On-demand | Flash sales, unknown traffic — pay per request, auto-scales | | Provisioned | Steady workloads — set RCU/WCU, use auto-scaling policies |

Write capacity: 1 WCU = one write/sec for item ≤ 1 KB (round up). Read capacity: 1 RCU = one strongly consistent read/sec for item ≤ 4 KB; eventual reads cost half.

VaultCommerce runs order tables on on-demand during holiday peaks and switches analytics replicas to provisioned baselines in off-season.

Quick recall

Everything you need if you only revisit this box.

  • Design tables from access patterns — every API path should map to GetItem or Query.
  • Composite keys enable range queries within a partition (orders by date).
  • Scan reads the whole table — admin-only, never customer-facing hot paths.
  • On-demand for spiky VaultCommerce traffic; provisioned when predictable.
  • RCU/WCU scale with item size — 10 KB writes cost 10 WCUs.
  • Hot partitions throttle despite "infinite scale" marketing — key design matters.

Test yourself

Answer these before moving on — recall is what makes it stick.