This chapter covers DynamoDB partition key design patterns, a critical topic for the SAA-C03 exam. Understanding how to choose and design partition keys directly impacts application performance, scalability, and cost. Expect 5-8% of exam questions to touch on DynamoDB design, with partition key selection being a common theme. You will learn the mechanics of partitioning, best practices for key design, and how to avoid hot partitions.
Jump to a section
Imagine a large library with millions of books. The library has a card catalog that helps you find books quickly. Each book has a unique ID (like a partition key) and a subject heading (like a sort key). The card catalog is organized into multiple drawers, each drawer holding cards for a range of book IDs. When you want to find a book, you go to the drawer that covers its ID range. Within that drawer, cards are sorted by subject heading, so you can easily locate the specific book. If you only search by subject heading without the ID, you'd have to check every drawer, which is slow. This is exactly how DynamoDB works: the partition key determines which partition (drawer) holds the item, and the sort key orders items within that partition. To design for performance, you need to ensure requests are evenly distributed across partitions—just like a librarian balancing books across drawers. A poorly chosen partition key (like using a timestamp that puts all today's books in one drawer) leads to a 'hot partition,' causing throttling. The best partition keys have high cardinality, like user IDs or device IDs, ensuring each drawer gets roughly equal traffic.
What is a Partition Key?
DynamoDB stores data across multiple partitions (physical storage nodes) based on the partition key. Each item's partition key value is hashed using an internal hash function to determine which partition stores the item. The partition key is part of the table's primary key; it can be simple (just the partition key) or composite (partition key + sort key). The partition key's cardinality (number of distinct values) directly affects how evenly data and requests are distributed across partitions.
How Partitioning Works Internally
When you create a DynamoDB table, you specify the partition key. DynamoDB uses a hash of the partition key value to map items to partitions. Each partition can hold up to 10 GB of data and support up to 3,000 read capacity units (RCUs) or 1,000 write capacity units (WCUs) for eventually consistent reads, or half that for strongly consistent reads. If your workload exceeds these limits, DynamoDB splits the partition. However, splitting is reactive and can cause throttling if the hot partition persists.
Key Components and Defaults
Partition Key (HASH): Required for every table. Used to distribute data across partitions.
Sort Key (RANGE): Optional. Sorts items within the same partition key. Allows range queries, filtering, and efficient retrieval of related items.
Local Secondary Index (LSI): Uses the same partition key but a different sort key. Must be defined at table creation.
Global Secondary Index (GSI): Has its own partition and sort keys. Can be added later. GSIs are essentially separate tables and consume their own capacity.
Provisioned Capacity: Each partition gets a slice of the table's provisioned capacity. For example, if you provision 1000 WCUs and there are 10 partitions, each partition gets 100 WCUs.
Adaptive Capacity: DynamoDB can automatically adjust partition splits and redistribute capacity to accommodate hot partitions, but it's not instantaneous.
Configuring and Verifying Partition Key Design
You cannot directly view partition distribution, but you can monitor CloudWatch metrics like ConsumedWriteCapacityUnits and ThrottledWriteEvents per partition using the ReturnItemCollectionMetrics parameter or by enabling DynamoDB Streams and analyzing logs. Use the DescribeTable API to see table metadata, but partition info is not exposed.
Interaction with Related Technologies
DAX (DynamoDB Accelerator): An in-memory cache that reduces read latency but does not solve partition key design issues; hot partitions still throttle writes.
Auto Scaling: Adjusts provisioned capacity but cannot fix a poorly chosen partition key; it only increases capacity across all partitions, which may not help if one partition is saturated.
DynamoDB Streams: Captures changes to items. If your partition key is poorly designed, streams may also experience throttling.
Design Patterns for Partition Keys
#### 1. High Cardinality Attributes
Use attributes with many distinct values, such as user ID, device ID, or order ID. This ensures even distribution. For example, if you have a table of user sessions, using user_id as the partition key distributes sessions evenly across partitions.
#### 2. Composite Key Using Sort Key
For one-to-many relationships, use a composite primary key. For example, for an orders table, use customer_id as partition key and order_date as sort key. This allows efficient queries for all orders of a customer within a date range.
#### 3. Write Sharding (Random Suffix)
To avoid hot partitions on a single value (e.g., a popular game leaderboard), add a random number suffix to the partition key. For example, instead of game_id, use game_id#1 through game_id#10. This spreads writes across 10 partitions. Reads must then query all shards and merge results.
#### 4. Write Sharding (Calculated Suffix)
Use a calculated suffix based on a hash of a secondary attribute. For example, for a table storing sensor readings, use sensor_type + hash(device_id) % 10. This provides even distribution while allowing some grouping.
#### 5. Using GSIs to Support Alternative Access Patterns
If your primary key design supports one access pattern well but you need another, create a GSI with a different partition key. For example, a table with user_id as partition key may need to query by email. Create a GSI with email as partition key. GSIs have their own capacity and can face hot partitions.
Common Pitfalls
Using Timestamps as Partition Keys: Timestamps often have low cardinality (e.g., only one value per second) and cause all writes to go to the same partition, leading to throttling.
Using Sequential IDs: Sequential IDs (e.g., auto-increment) are monotonically increasing, causing hot partitions. Use UUIDs or KSUIDs instead.
Ignoring Sort Key: Not using a sort key when you need range queries forces you to scan the entire table, which is inefficient and expensive.
Overusing GSIs: Each GSI consumes additional storage and capacity. Too many GSIs can increase costs and complexity.
Performance Considerations
Read/Write Capacity: Each partition supports up to 3000 RCUs or 1000 WCUs. If your partition key design causes a single partition to exceed these limits, you'll get ProvisionedThroughputExceededException.
Item Size: Max item size is 400 KB. Large items consume more capacity and may cause uneven distribution if partition key values are not well-distributed.
Burst Capacity: DynamoDB provides burst capacity (up to 5 minutes of unused capacity) but it's not a substitute for good design.
Advanced Patterns
#### 1. Time Series Data
For time series data, use a composite key with a truncated timestamp as partition key (e.g., day) and full timestamp as sort key. This allows efficient queries for a specific day. For hot days, use sharding.
#### 2. Multi-Tenant Systems
Use tenant_id as partition key. If tenants have uneven workloads, consider sharding within a tenant (e.g., tenant_id#shard_id).
#### 3. Global Tables
Global Tables replicate data across regions. Partition key design becomes even more critical because hot partitions affect all regions. Use high-cardinality keys to avoid cross-region throttling.
Identify Access Patterns
List all queries your application will perform. Determine which attributes are used for lookups (equality conditions) and which are used for range queries (sorting, filtering). This defines your primary key design. For each access pattern, note the expected frequency and whether reads or writes dominate. This step is crucial because DynamoDB requires you to design for access patterns upfront; you cannot change the primary key later without creating a new table.
Choose High-Cardinality Partition Key
Select a partition key attribute with many distinct values, such as a UUID or user ID. Avoid low-cardinality keys like status flags (e.g., 'active', 'inactive') or timestamps. High cardinality ensures even distribution of data and requests across partitions. For example, a table of 10 million users using `user_id` as partition key will have each user on a different partition, achieving perfect distribution.
Define Sort Key for Range Queries
If you need to query items with the same partition key in a sorted order or filter by a range (e.g., date range), add a sort key. The sort key can be a timestamp, a number, or a string. Composite keys allow efficient `Query` operations using `KeyConditionExpression` with `BETWEEN`, `>`, `<`, etc. Without a sort key, you would need to scan and filter, which is expensive.
Evaluate Sharding for Hot Keys
If a single partition key value (e.g., a popular product ID) receives high write traffic, consider sharding. Add a random or calculated suffix to the partition key to distribute writes across multiple partitions. For example, use `product_id#shard_id` where `shard_id` is a random number 1-10. Reads must then query all shards and merge results. This pattern is especially useful for write-heavy workloads like logging or leaderboards.
Use GSIs for Alternative Patterns
If you have additional access patterns not covered by the primary key, create one or more GSIs. Each GSI has its own partition and sort keys. For example, if your main table uses `user_id` as partition key, but you also need to query by `email`, create a GSI with `email` as partition key. GSIs have separate capacity and can experience throttling independently. Monitor GSI metrics in CloudWatch.
Enterprise Scenario 1: Gaming Leaderboard
A gaming company stores player scores in a DynamoDB table. Initially, they used game_id as partition key and player_id as sort key. During a popular event, one game received millions of writes per second, causing throttling on that single partition. The solution was to shard the partition key by adding a random suffix (game_id#shard where shard is 0-99). Writes were distributed across 100 partitions. Reads required querying all shards and merging, but the leaderboard could be updated asynchronously with a pre-computed result. This pattern is documented in AWS re:Invent talks and is a common exam scenario.
Enterprise Scenario 2: IoT Sensor Data
A manufacturing company collects temperature readings from thousands of sensors every second. They used sensor_id as partition key and timestamp as sort key. However, some sensors reported more frequently, causing hot partitions. They implemented calculated sharding: sensor_id + (hash(sensor_id) % 10). This distributed writes evenly. They also used a GSI with timestamp as partition key for time-range queries across all sensors. The main table handled per-sensor queries efficiently, while the GSI supported global analytics. This design is typical for IoT workloads and appears in SAA-C03 questions about DynamoDB design.
Enterprise Scenario 3: E-Commerce Order History
An e-commerce platform stores orders with customer_id as partition key and order_date as sort key. This allows fast retrieval of a customer's orders in chronological order. However, they also needed to support queries by order status (e.g., all pending orders). They created a GSI with status as partition key and order_date as sort key. But status has low cardinality (pending, shipped, delivered), so writes to the GSI were concentrated on a few partitions. To mitigate, they used write sharding on the GSI partition key: status#shard_id. This is a real-world pattern from AWS documentation and a potential exam trick.
SAA-C03 Objective 3.6: Design High-Performance Architectures
The exam tests your ability to design DynamoDB tables for performance. Key areas: - Partition key selection: You must choose a high-cardinality attribute. Common wrong answer: using a timestamp or status field as partition key. - Hot partitions: Questions describe a scenario where a table throttles despite low overall utilization. The solution is to redesign the partition key (e.g., add sharding) or use a GSI with a different key. - GSI vs. LSI: LSIs use the same partition key as the table and must be created at table creation. GSIs can be added later and have independent capacity. The exam may ask which to use for a new access pattern. - Read/write capacity per partition: Each partition supports up to 3000 RCUs (eventually consistent) or 1000 WCUs. If a single partition key value receives more, throttling occurs.
Common Wrong Answers
'Increase provisioned capacity' – This does not fix a hot partition because capacity is distributed across all partitions. The hot partition still gets only its share.
'Use DynamoDB Auto Scaling' – Same issue; Auto Scaling increases overall capacity but does not redistribute it to a hot partition.
'Add a GSI with the same partition key' – This does not solve the hot partition; the GSI will have the same bottleneck.
'Use a sort key to distribute writes' – Sort key does not affect partition distribution; only partition key determines partition.
Exam Tips
Always look for the root cause: if throttling occurs on a single partition, the partition key is the problem.
Sharding (adding a random suffix) is the correct solution for a hot partition key.
For read-heavy hot partitions, consider DAX or a GSI with a different partition key.
Remember that LSIs cannot be added after table creation; GSIs can.
The exam loves scenarios where a timestamp is used as partition key leading to throttling during peak hours.
Each DynamoDB partition can support up to 3,000 RCUs (eventually consistent) or 1,000 WCUs.
Partition key must have high cardinality to avoid hot partitions; avoid timestamps, status fields, or sequential IDs.
To fix a hot partition, use write sharding by adding a random or calculated suffix to the partition key.
LSIs must be created at table creation; GSIs can be added later and have their own capacity.
DynamoDB Auto Scaling increases total capacity but does not redistribute capacity to hot partitions.
Use sort keys for range queries; without a sort key, you must use Scan which is inefficient.
Global tables replicate data across regions; partition key design must avoid hot partitions in all regions.
These come up on the exam all the time. Here's how to tell them apart.
Simple Primary Key (Partition Key only)
Only partition key attribute
No sort key
Cannot do range queries; only GetItem or Query with exact partition key
Items with same partition key cannot be ordered or filtered efficiently
Useful when each partition key has only one item
Composite Primary Key (Partition Key + Sort Key)
Partition key + sort key
Sort key can be string, number, or binary
Allows Query with KeyConditionExpression for range queries
Items with same partition key are sorted by sort key
Supports one-to-many relationships (e.g., customer orders)
Mistake
Increasing provisioned capacity always solves throttling.
Correct
Throttling can be due to a hot partition. Each partition has a max of 3000 RCUs/1000 WCUs. Increasing provisioned capacity only adds capacity to new partitions; existing hot partitions remain limited until they split.
Mistake
The sort key distributes data across partitions.
Correct
Only the partition key determines which partition stores an item. The sort key only orders items within the same partition key. Changing the sort key does not affect distribution.
Mistake
GSIs have the same partition limits as the base table.
Correct
GSIs have their own provisioned capacity and partition limits. A hot partition in the base table does not directly cause throttling in the GSI, but a poorly designed GSI partition key can cause its own hot partitions.
Mistake
Using a UUID as partition key guarantees even distribution.
Correct
UUIDs are high-cardinality and generally distribute well, but if the UUID is generated sequentially (e.g., time-based UUIDs), it can cause hot partitions. Use random UUIDs or hash-based keys.
Mistake
DynamoDB Auto Scaling prevents hot partitions.
Correct
Auto Scaling adjusts total capacity but does not redistribute capacity among partitions. A hot partition will still exceed its per-partition limits.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
A hot partition occurs when one partition key value receives a disproportionate amount of traffic, exceeding the partition's capacity limits (3,000 RCUs or 1,000 WCUs). Symptoms: throttling errors despite low overall utilization. Fix by redesigning the partition key: either choose a high-cardinality attribute or use write sharding (add a random suffix to the partition key). For reads, you can also use DAX or a GSI with a different partition key.
Use a composite primary key (partition key + sort key) when you need to query multiple items that share the same partition key and you want to sort or filter them. For example, storing all orders for a customer: use customer_id as partition key and order_date as sort key. Use a simple primary key when each partition key value corresponds to exactly one item (e.g., a user profile table with user_id as partition key).
No, you cannot change the partition key of an existing table. You must create a new table with the desired key design, then migrate data using DynamoDB Streams or AWS Data Pipeline. This is a common exam point: design your partition key carefully before creating the table.
LSI (Local Secondary Index) uses the same partition key as the table but a different sort key. It must be created at table creation. GSI (Global Secondary Index) has its own partition key and sort key, can be created anytime, and has its own provisioned capacity. LSIs are limited to 5 per table; GSIs up to 20. LSIs support strongly consistent reads; GSIs support only eventually consistent reads.
Use CloudWatch metrics `ThrottledWriteEvents` and `ThrottledReadEvents` with the dimension `Operation` and `TableName`. However, these are aggregate. To identify hot partitions, enable DynamoDB Streams and analyze the stream records, or use AWS X-Ray to trace requests. You can also use the `ReturnItemCollectionMetrics` parameter to see collection size.
Write sharding is a technique where you add a random or calculated suffix to the partition key to distribute writes across multiple partitions. Use it when a single partition key value (e.g., a popular product ID) receives very high write traffic that exceeds a single partition's capacity. For example, use `product_id#shard_id` where shard_id is 1-10. Reads must query all shards and merge results.
No. Auto Scaling adjusts the table's total provisioned capacity based on average utilization, but it does not redistribute capacity among partitions. A hot partition will still be limited to its per-partition maximum (3,000 RCUs or 1,000 WCUs). You must fix the partition key design to resolve hot partitions.
You've just covered DynamoDB Partition Key Design Patterns — now see how well it sticks with free SAA-C03 practice questions. Full explanations included, no account needed.
Done with this chapter?