Skip to main content

Amazon DynamoDB

Exam focus: DynamoDB is one of the top 3 most tested services in DVA-C02. Know the key design, capacity, and consistency options cold.


Core Conceptsโ€‹

Primary Key Typesโ€‹

TypeDescriptionWhen to use
Partition Key (Hash Key)Single attribute, must be uniqueSimple lookups by ID
Partition Key + Sort KeyComposite key โ€” partition must be unique per sort key comboHierarchical data (userId + timestamp)
Key Design Rule

Design your partition key for even distribution. Bad partition keys (like status = "active") create hot partitions and throttling.

โœ… Good: userId, orderId (unique, uniform)
โŒ Bad: country, status (low cardinality, hot partitions)


Read/Write Capacity Modesโ€‹

ModeDescriptionBest For
ProvisionedSet RCUs and WCUs manuallyPredictable, steady workloads
On-DemandAuto-scales, pay per requestUnpredictable, spiky workloads

Capacity Unitsโ€‹

1 RCU = 1 strongly consistent read of โ‰ค4KB/s
= 2 eventually consistent reads of โ‰ค4KB/s
= ยฝ transactional read of โ‰ค4KB/s

1 WCU = 1 write of โ‰ค1KB/s
= ยฝ transactional write of โ‰ค1KB/s

Example: Read 10 items of 6KB each per second, strongly consistent
โ†’ Each item needs: ceil(6/4) = 2 RCUs
โ†’ Total: 10 ร— 2 = 20 RCUs


Read Consistencyโ€‹

ModeLatencyFreshness
Eventually ConsistentLowMay return stale data (replicated within ~1s)
Strongly ConsistentHigherAlways returns the latest data โ€” costs 2ร— RCUs
TransactionalHighestACID guarantee across multiple items

Secondary Indexesโ€‹

Local Secondary Index (LSI)โ€‹

  • Same partition key, different sort key
  • Must be created at table creation time
  • Shares the table's RCU/WCU
  • Max 5 LSIs per table

Global Secondary Index (GSI)โ€‹

  • Different partition key and/or sort key
  • Can be created or deleted any time
  • Has its own RCU/WCU provisioning
  • Supports eventual consistency only
  • Max 20 GSIs per table
Exam Rule

Need to query on a non-key attribute? โ†’ GSI
Need a different sort key for the same partition? โ†’ LSI


DynamoDB Streamsโ€‹

  • Captures item-level changes (INSERT, MODIFY, REMOVE)
  • Records available for 24 hours
  • Can trigger Lambda (Event Source Mapping)

Stream View Typesโ€‹

View TypeContent
KEYS_ONLYOnly the key attributes
NEW_IMAGEThe entire new item after change
OLD_IMAGEThe entire old item before change
NEW_AND_OLD_IMAGESBoth before and after (most expensive)

Use Casesโ€‹

  • Replicate table to another region
  • Trigger Lambda on data change
  • Audit trail
  • Build materialized views / aggregations

DAX (DynamoDB Accelerator)โ€‹

  • In-memory cache โ€” microsecond latency (vs milliseconds for DynamoDB)
  • Write-through: writes go to both DAX and DynamoDB
  • Cluster sits in front of DynamoDB โ€” app uses DAX client
  • Best for read-heavy workloads
  • Does not support strongly consistent reads or transactions
DAX vs ElastiCache
  • DAX โ€” DynamoDB-specific, transparent drop-in cache, AWS-managed
  • ElastiCache โ€” General-purpose cache (Redis/Memcached), used for any DB

Transactionsโ€‹

// All-or-nothing: debit one account, credit another
var result = dynamoDbClient.transactWriteItems(TransactWriteItemsRequest.builder()
.transactItems(
TransactWriteItem.builder()
.update(Update.builder()
.tableName("Accounts")
.key(Map.of("accountId", AttributeValue.fromS("ACC-001")))
.updateExpression("SET balance = balance - :amount")
.expressionAttributeValues(Map.of(":amount", AttributeValue.fromN("100")))
.conditionExpression("balance >= :amount")
.build())
.build(),
TransactWriteItem.builder()
.update(Update.builder()
.tableName("Accounts")
.key(Map.of("accountId", AttributeValue.fromS("ACC-002")))
.updateExpression("SET balance = balance + :amount")
.expressionAttributeValues(Map.of(":amount", AttributeValue.fromN("100")))
.build())
.build()
)
.build());
  • Up to 100 items or 4MB per transaction
  • Consumes 2ร— the RCUs/WCUs of non-transactional operations

Key API Operationsโ€‹

OperationDescription
PutItemCreate or replace item
GetItemRead single item by key
UpdateItemUpdate specific attributes
DeleteItemDelete item by key
QueryRead items with same partition key (and optional sort key filter)
ScanRead all items in table (expensive, avoid in production)
BatchGetItemUp to 100 items from multiple tables
BatchWriteItemUp to 25 PutItem/DeleteItem operations
TransactGetItemsAtomic reads from multiple items
TransactWriteItemsAtomic writes to multiple items
Scan is expensive

Scan reads the entire table โ€” use filters but they don't reduce RCU cost (filtering happens after read). Always prefer Query or design GSIs to avoid scans.


TTL (Time to Live)โ€‹

{
"userId": "user-123",
"sessionData": "...",
"expiresAt": 1734567890 // Unix epoch โ€” DynamoDB deletes when this timestamp passes
}
  • Free, no RCU/WCU consumed for deletions
  • Deletions happen within 48 hours of expiry (eventually consistent)
  • Expired items are not immediately deleted โ€” filter expiresAt > now() in your queries

Conditional Writesโ€‹

// Only update if version matches (Optimistic Locking)
dynamoDbClient.updateItem(UpdateItemRequest.builder()
.tableName("Products")
.key(Map.of("productId", AttributeValue.fromS("P-001")))
.updateExpression("SET price = :newPrice, version = version + :inc")
.conditionExpression("version = :expectedVersion")
.expressionAttributeValues(Map.of(
":newPrice", AttributeValue.fromN("99.99"),
":inc", AttributeValue.fromN("1"),
":expectedVersion", AttributeValue.fromN("5")
))
.build());

๐Ÿงช Practice Questionsโ€‹

Q1. A developer needs to find all orders for a specific customer sorted by date. The table has customerId as partition key and orderId as sort key. What is the MOST efficient approach?

A) Scan with filter expression
B) Query on partition key = customerId, sort by date
C) Create a GSI with partition key = customerId, sort key = orderDate, then Query
D) GetItem for each orderId

โœ… Answer & Explanation

C โ€” The current sort key is orderId, so you can't sort by date with just a Query. A GSI with partition key = customerId and sort key = orderDate allows efficient queries sorted by date. (B is almost right, but the sort key is orderId not date.)


Q2. A table has 10 items of 10KB each. A developer runs a Scan operation. How many RCUs are consumed with eventually consistent reads?

A) 5
B) 10
C) 20
D) 25

โœ… Answer & Explanation

D โ€” Each 10KB item needs ceil(10/4) = 3 RCUs for strongly consistent, 1.5 (round up to 2?) wait โ€” let me recalculate:

  • 10KB per item / 4KB per RCU = 2.5 โ†’ ceil = 3 RCUs per item (strongly consistent)
  • Eventually consistent = 3/2 = 1.5 โ†’ ceil = 2 RCUs per item
  • 10 items ร— 2 = 20 RCUs
    Answer: C โ€” 20 RCUs

Q3. Which DynamoDB Stream view type captures both the old and new item state for every change?

A) KEYS_ONLY
B) NEW_IMAGE
C) OLD_IMAGE
D) NEW_AND_OLD_IMAGES

โœ… Answer & Explanation

D โ€” NEW_AND_OLD_IMAGES captures both states, useful for auditing what changed.


Q4. A team needs sub-millisecond read latency on DynamoDB. What should they use?

A) ElastiCache Redis
B) Read Replicas
C) DAX
D) Strongly Consistent Reads

โœ… Answer & Explanation

C โ€” DAX provides microsecond latency for DynamoDB reads (it's an in-memory write-through cache). Strongly consistent reads are slower, not faster.


๐Ÿ”— Resourcesโ€‹