Jump to Category
| 🏗️ Data Modeling & Core Concepts | 🚀 Indexing Strategies |
| 🔍 Querying & Performance | 🌐 Scalability & High Availability |
| ✨ Advanced Features & Transactions |
Data Modeling & Core Concepts
1. Explain the importance of choosing a good partition key. What happens if you choose a poor one?
The **partition key** determines the physical partition where data is stored. DynamoDB hashes the partition key value to distribute data evenly across multiple partitions. A good partition key has high cardinality (many unique values) and is accessed uniformly, which ensures that read/write traffic is spread evenly across the partitions.
Choosing a poor partition key (one with low cardinality or one that is accessed much more frequently than others) leads to a **”hot partition”**. A hot partition receives a disproportionate amount of traffic, causing throttling and performance bottlenecks for that specific key, even if the table’s overall provisioned throughput is not exceeded.
Read the AWS blog on choosing a partition key.2. What is a composite primary key and how does it affect querying?
A composite primary key is made up of two attributes: a **partition key** and a **sort key**. All items with the same partition key are stored together, physically sorted by the sort key value.
This structure is powerful for querying. You can efficiently query for all items with a specific partition key. Furthermore, you can apply conditions to the sort key to retrieve a specific range of items within that partition, using operators like `begins_with`, `between`, `>`, and `
3. Explain the concept of a single-table design in DynamoDB. What are its pros and cons?
Single-table design is an advanced data modeling pattern where multiple different entity types (e.g., `Users`, `Orders`, `Products`) are stored in a single DynamoDB table. This is achieved by using a generic primary key (e.g., `PK`, `SK`) and overloading it with different values to represent different entities and relationships.
Pros:
- Performance: It allows you to fetch multiple different but related item types in a single query, minimizing the number of requests and reducing latency.
- Cost: Fewer requests can lead to lower costs, especially in on-demand mode.
- Complexity: It’s more complex to design, query, and reason about compared to a multi-table relational model.
- Flexibility: Ad-hoc queries are much more difficult. You must design your table specifically for your application’s access patterns.
4. What are Read and Write Capacity Units (RCUs/WCUs)? How are they calculated?
RCUs and WCUs are the units of throughput for provisioned capacity mode.
- 1 RCU represents one strongly consistent read per second, or two eventually consistent reads per second, for an item up to 4 KB in size.
- 1 WCU represents one write per second for an item up to 1 KB in size.
For items larger than these sizes, more units are consumed. For example, a 10 KB strongly consistent read would consume `ceil(10 / 4) = 3` RCUs. A 5 KB write would consume `ceil(5 / 1) = 5` WCUs.
Read the docs on Read/Write Capacity Mode.5. Compare Provisioned Throughput and On-Demand capacity modes.
- Provisioned Throughput: You specify the number of RCUs and WCUs your application requires. This mode is best for applications with predictable, consistent traffic, as it’s generally more cost-effective if you can accurately predict your workload. You can use auto-scaling to adjust capacity.
- On-Demand: You pay per request (per million reads/writes). DynamoDB automatically scales to handle your workload instantly. This mode is best for applications with unpredictable, spiky traffic or for new applications where the workload is unknown. It’s simpler to manage but can be more expensive for high, sustained traffic.
Indexing Strategies
6. What is the difference between a Local Secondary Index (LSI) and a Global Secondary Index (GSI)?
Both allow you to query data using an alternative key, but they have fundamental differences.
- Local Secondary Index (LSI):
- Must share the same partition key as the base table but can have a different sort key.
- Can only be created when the table is created.
- Shares the provisioned throughput of the base table.
- Queries provide strongly consistent reads.
- There is a 10 GB size limit for all items that share the same partition key.
- Global Secondary Index (GSI):
- Can have a partition key and sort key that are completely different from the base table.
- Can be created or deleted at any time.
- Has its own provisioned throughput, separate from the base table.
- Queries are eventually consistent.
7. What are projected attributes in a GSI and how do they affect performance and cost?
When you create a GSI, you must specify which attributes from the base table are “projected” (copied) into the index. You can choose:
- KEYS_ONLY: Only the primary keys of the table and the index are projected. This creates the smallest index and is cheapest.
- INCLUDE: The keys plus a specified list of additional attributes are projected.
- ALL: All attributes from the base table item are projected. This creates the largest index and is most expensive.
This affects performance because if all the attributes your query needs are projected into the index, DynamoDB can satisfy the query from the GSI alone (a “covered query”). If not, it must perform an extra read from the base table, incurring additional latency and cost.
8. What is a sparse index?
A sparse index is a GSI that only contains entries for items that have the index’s key attribute present in the base table. If an item in the base table does not have the attribute defined for the GSI’s key, it will not appear in the index at all.
This is useful for efficiently querying over a small subset of items in a large table. For example, you could have a `is_active_promotion` attribute on a `products` table and create a GSI on it. The GSI would only contain the products that are currently part of a promotion, making it very small and fast to query.
9. What is GSI overloading?
GSI overloading is an advanced single-table design pattern where a single GSI is used to support multiple, different query patterns. This is achieved by populating the GSI’s key attributes with different types of data based on the item type. For example, for a `User` item, the `GSI1PK` might hold their email address. For an `Order` item, the same `GSI1PK` might hold the product SKU. This allows you to query for users by email and orders by SKU using the same index, reducing the number of GSIs needed and thus lowering costs.
Querying & Performance
10. Explain the difference between a `Query` and a `Scan` operation. Why should you avoid scans?
- `Query`: A highly efficient operation that finds items based on primary key values. You must provide the partition key, and you can optionally provide conditions on the sort key.
- `Scan`: Reads *every single item* in an entire table or secondary index. It then filters the results to find the values you want.
You should avoid scans in production applications because they are extremely inefficient and expensive. A scan can consume a huge amount of provisioned throughput and its performance degrades linearly as the table grows. It’s almost always a sign of a data modeling problem; you should use a `Query` on a table or a GSI instead.
11. What is DynamoDB’s adaptive capacity feature?
Adaptive capacity is a feature that automatically mitigates issues with hot partitions. If it detects a partition receiving a disproportionate amount of traffic, DynamoDB will automatically and instantly increase the throughput capacity of that partition. It allows a hot partition to “burst” and consume the table’s unused capacity, up to the table’s total provisioned limit. This helps smooth out uneven traffic patterns without requiring manual intervention, but it’s not a substitute for good partition key design.
12. What is a write-sharding strategy used for?
Write sharding is a technique used to avoid hot partitions when you have a low-cardinality partition key but high write throughput. Instead of using a simple partition key like `user_id`, you append a random number from a fixed range (e.g., 1-10) to it, creating keys like `user_id-1`, `user_id-2`, etc. This spreads the writes for that single logical item across multiple physical partitions. When you need to read the data, you must query all 10 possible partitions and merge the results in your application.
13. What are eventually consistent vs. strongly consistent reads?
- Eventually Consistent Read (default): The response might not reflect the results of a recently completed write. The data is typically consistent within a second. This type of read is half the cost (consumes half the RCUs) of a strongly consistent read.
- Strongly Consistent Read: The response is guaranteed to reflect all writes that received a successful response prior to the read. This provides the most up-to-date data but has higher latency and costs twice as much in RCUs. GSIs do not support strongly consistent reads.
14. What are filter expressions and projection expressions?
- A **Filter Expression** is used with a `Scan` or `Query` to remove items from the result set *after* they have been read from the table but before they are returned to the client. It’s important to note that you are still charged for the read capacity of the filtered-out items.
- A **Projection Expression** is used to specify which attributes of an item you want to retrieve. Using a projection expression is a best practice for performance and cost, as it reduces the amount of data transferred over the network.
Scalability & High Availability
15. What are DynamoDB Global Tables?
Global Tables provide a fully managed, multi-region, multi-active database solution. A global table consists of multiple replica tables in different AWS Regions. DynamoDB automatically propagates any write to one replica table to all other replicas, typically within a second.
This is ideal for globally distributed applications that require low-latency data access for users in different geographical locations and provides a robust disaster recovery solution. Conflict resolution is handled on a “last writer wins” basis.
Read the AWS page on Global Tables.16. What is DynamoDB Accelerator (DAX)? When should you use it?
DAX is a fully managed, highly available, in-memory cache for DynamoDB. It sits in front of your DynamoDB tables and provides microsecond read latency for cached items. It is API-compatible with DynamoDB, so you can use it with minimal code changes.
You should use DAX for read-heavy applications that require extremely low latency (e.g., real-time bidding or social media feeds), and where the cost of a strongly consistent read from DynamoDB itself is a bottleneck. It is not suitable for write-heavy applications or those that require strongly consistent reads for all operations, as DAX reads are eventually consistent.
Learn more about DynamoDB Accelerator (DAX).17. Explain Point-in-Time Recovery (PITR).
Point-in-Time Recovery is a feature that provides continuous backups of your DynamoDB table data. When enabled, DynamoDB maintains incremental backups, allowing you to restore your table to any point in time during the last 35 days with per-second precision. This is a critical feature for protecting against accidental writes or deletes, providing a powerful disaster recovery mechanism without you needing to manage snapshots manually.
Advanced Features & Transactions
18. How do ACID transactions work in DynamoDB?
DynamoDB provides ACID transactions for coordinating multiple read or write operations across multiple items within one or more tables in the same AWS account and region.
- `TransactWriteItems`: A synchronous write operation that groups up to 100 `Put`, `Update`, or `Delete` actions into a single all-or-nothing operation. If any single action fails (e.g., due to a failed conditional check), the entire transaction is rolled back.
- `TransactGetItems`: A synchronous read operation that retrieves up to 100 items, providing transactional guarantees for reads.
These operations provide transactional guarantees similar to those in relational databases.
Read about DynamoDB Transactions.19. What are DynamoDB Streams? Provide a common use case.
DynamoDB Streams capture a time-ordered sequence of item-level modifications (inserts, updates, deletes) in a DynamoDB table. The stream record contains information about the data modification, such as the before and after images of the item.
A common use case is to create an event-driven architecture by connecting the stream to an AWS Lambda function. For example, a Lambda trigger on a `Users` table stream could automatically send a welcome email whenever a new user item is created, or a trigger on an `Orders` table could update an analytics dashboard in real-time.
Explore the DynamoDB Streams documentation.20. What are conditional writes and how are they used for optimistic locking?
A conditional write (`Put`, `Update`, `Delete`) will only succeed if a specified `ConditionExpression` evaluates to true. If the condition is not met, the operation fails with a `ConditionalCheckFailedException`.
This is the primary mechanism for implementing optimistic locking. You can add a `version` attribute to your items. When updating an item, you provide a condition that the `version` attribute in the database must match the version you last read. If it matches, the update proceeds and increments the version number. If not, it means another process has modified the item, and the write fails, allowing your application to handle the conflict.
21. What is the Time To Live (TTL) feature?
TTL allows you to define a per-item timestamp to determine when that item is no longer needed. You specify a specific attribute name to act as the TTL attribute. This attribute must store a timestamp in Unix epoch time format. DynamoDB will periodically scan for items where the TTL timestamp has expired and delete them from the table automatically, typically within 48 hours of expiration. This is a free-of-charge way to remove stale data, perfect for things like user sessions or temporary records.
22. Can you perform joins in DynamoDB?
No, DynamoDB is a NoSQL database and does not support server-side joins like a relational database. The recommended approach is to design your data models to avoid the need for joins.
This can be achieved by:
- Denormalization: Embedding related data within a single document.
- Single-Table Design: Fetching different but related entities in a single `Query` operation.
- Application-Side Joins: Performing two separate queries from your application and joining the results in your code. The `$lookup` stage in the Aggregation Framework can also perform a server-side “join” but has limitations.
23. What is the maximum item size in DynamoDB?
The maximum size for a single item in DynamoDB, including both its attribute names and values, is **400 KB**. If you need to store data larger than this, you should consider using Amazon S3 and storing a pointer (the S3 object key) to the data in your DynamoDB item. GridFS is another pattern for this, though less common with S3 available.
24. What is the difference between an atomic counter and a standard update?
An atomic counter is an update operation that uses an `UpdateExpression` with a `SET` action to increment or decrement a numeric attribute (e.g., `SET score = score + :val`). This operation is atomic; it reads the value, adds to it, and saves the new value as a single, indivisible operation. This is crucial for scenarios like tracking counters or scores, as it prevents lost updates that could occur if you were to read the value, increment it in your application, and then write it back.
25. How do you implement fine-grained access control for items in a table?
You can use **IAM policies** with condition keys to achieve fine-grained access control. An IAM policy can grant a user or role access to specific DynamoDB actions (like `GetItem` or `PutItem`) but can be restricted with a condition. A common pattern is to include a condition that checks if the `leadingKeys` of the primary key match a user’s identity (e.g., their user ID). This allows you to create IAM policies that, for example, only allow a user to read or write items where the partition key matches their own user ID.