← Week 2: DynamoDB Internals

Day 13: DynamoDB Advanced Patterns

Phase 5 · Aug 24, 2026

← Week 2: DynamoDB Internals

Agenda (2–3 hours)

  • Read (45 min): DynamoDB adjacency list pattern; GSI overloading; write sharding documentation
  • Study (45 min): Model a social graph (followers, following) as an adjacency list in DynamoDB; support "who follows Alice?" and "who does Alice follow?"
  • Practice (45 min): Implement write sharding for a "global leaderboard" table; verify even partition distribution with 10,000 writes
  • Challenge (30 min): DynamoDB Condition Expressions are evaluated server-side. Design a pattern for "add to set if not exceeds limit" (e.g., max 100 items in a list attribute)
← Week 2: DynamoDB Internals

Adjacency List Pattern

Model many-to-many relationships:

PK          SK          GSI1-PK     GSI1-SK
USER#alice  USER#alice  -           -          # user profile
USER#alice  FOLLOWS#bob USER#bob    FOLLOWED_BY#alice   # alice follows bob
USER#bob    FOLLOWS#carol USER#carol FOLLOWED_BY#bob    # bob follows carol

Queries:

  • "Who does Alice follow?" → PK = USER#alice, SK begins_with FOLLOWS#
  • "Who follows Bob?" → GSI query: GSI1-PK = USER#bob, GSI1-SK begins_with FOLLOWED_BY#

Both queries served by the same table with different access paths.

← Week 2: DynamoDB Internals

GSI Overloading

A GSI can serve multiple entity types by using generic attribute names:

PK          SK           gsi1pk          gsi1sk
ORDER#42    STATUS       PENDING         2026-08-24   # pending order
ITEM#99     CATEGORY     electronics     ITEM#99      # item by category
USER#alice  CITY         NYC             USER#alice   # user by city

One GSI serves three different query patterns by reusing gsi1pk/gsi1sk for different purposes per entity type. Reduces cost (fewer GSIs) at the expense of model complexity.

← Week 2: DynamoDB Internals

Write Sharding for Hot Partitions

Problem: leaderboard with partition key game_id → all writes to one partition.

Solution: shard the partition key:

let shard = rand::random::<u8>() % 10; // 0-9
let pk = format!("GAME#{}-SHARD#{}", game_id, shard);

// Write to sharded key
dynamodb.put_item()
    .item("pk", AttributeValue::S(pk))
    .item("score", AttributeValue::N(score.to_string()))
    .send().await?;

// Read: must query all 10 shards and aggregate
let reads = (0..10).map(|shard| query_shard(game_id, shard));
let results = join_all(reads).await;
let total_score: u64 = results.iter().flat_map(|r| r).sum();
← Week 2: DynamoDB Internals

Composite Sort Keys for Range Queries

Sort key encodes multiple fields for range queries:

SK = "YEAR#2026#MONTH#08#DAY#24#ORDER#abc123"

Enables:

  • SK = "YEAR#2026#MONTH#08#DAY#24" → exact date
  • SK begins_with "YEAR#2026#MONTH#08" → all of August
  • SK between "YEAR#2026#MONTH#01" AND "YEAR#2026#MONTH#06" → Jan–Jun
← Week 2: DynamoDB Internals

Key Takeaways

  • Adjacency list: model many-to-many relationships with two GSI access patterns
  • GSI overloading: reuse GSI attribute names across entity types for cost efficiency
  • Write sharding: spread hot partitions by adding random suffix; reads must aggregate across shards
  • Composite sort keys encode multiple filter dimensions for rich range queries

Tomorrow: Phase 5 Week 2 Challenge — implement a single-table DynamoDB schema.