These patterns let a few indexes serve many access patterns and keep heavy traffic evenly spread.
A few patterns come up in nearly every serious DynamoDB design:
- Sparse index: only items that have the index's key attribute are indexed. Set
open_sinceonly on open orders and a GSI on it lists exactly the open ones; remove the attribute when the order closes and it drops out. Small, cheap, and a natural work queue. - GSI overloading: give the index generic keys (
GSI1PK,GSI1SK) and let each entity type put a different meaning in them: orders bySTATUS#PENDING, users byEMAIL#.... One index then serves many patterns, which matters because each GSI adds write cost. - Inverted index: a GSI whose partition key is the table's sort key and vice versa, so many-to-many relationships can be read from both sides (students of a class, classes of a student).
- Write sharding: if one key value gets too much traffic (a global leaderboard, today's date), append a random or calculated suffix
DATE#2025-03-01#7across N shards, and query all N shards in parallel when reading.
Also consider composite sort keys like COUNTRY#STATE#CITY so begins_with queries at any level work from one index.
Every pattern costs something: duplicated storage, extra writes, more complex reads. Add them for real access patterns only.
Example
import random
import boto3
from boto3.dynamodb.conditions import Key
table = boto3.resource("dynamodb").Table("App") # GSI "GSI1" on (GSI1PK, GSI1SK)
SHARDS = 4
def record_vote(day, user):
shard = random.randrange(SHARDS) # spread one hot day over 4 keys
table.put_item(Item={"PK": f"VOTE#{user}", "SK": day,
"GSI1PK": f"DAY#{day}#{shard}", "GSI1SK": user})
def votes_for(day):
items = []
for s in range(SHARDS): # read every shard
items += table.query(IndexName="GSI1",
KeyConditionExpression=Key("GSI1PK").eq(f"DAY#{day}#{s}"))["Items"]
return items
for u in ["ann", "bob", "cy"]:
record_vote("2025-03-01", u)
print(sorted(i["GSI1SK"] for i in votes_for("2025-03-01"))) # ['ann', 'bob', 'cy']Remember
- Sparse GSIs index only items that carry the key attribute
- Overloaded generic GSI keys let one index serve many patterns
- Inverted indexes read many-to-many relations from both sides
- Write sharding spreads a hot key; reads fan out across shards
Watch out for
- Sharding a key that is not actually hot, which only multiplies read requests.