How do you store millions of customer records and retrieve any single one in less than a tenth of a second, without making your database slow down as it grows? That is the problem Amazon DynamoDB solves, and it is critical for the DVA-C02 exam because you will be asked to design tables, choose primary keys, and use indexes to make queries fast – and if you get it wrong, your application will either cost too much or perform terribly.
Jump to a section
A simple way to picture Amazon DynamoDB: Tables, Queries, and Indexes
Have you ever wondered how a food truck with one tiny order book can serve hundreds of customers without getting confused?
A food truck has a single spiral-bound notebook called the 'Orders Table'. Every order is a row in that table, and the truck gives each order a unique 'Order ID' (like a receipt number) – this is the primary key. The truck only has one rule: you must look up an order by its Order ID, otherwise you have to flip through every single page, which takes forever (that's a scan).
Now imagine the same truck wants to sort orders by 'Customer Name' to quickly find all orders from a regular. To do that without flipping through the whole book, the truck writes a separate index card system – a 'Global Secondary Index' (GSI). Every time a new order is written in the main book, the truck also writes a card sorted by Customer Name. That card points to the page number of the full order.
But there's a catch: if the truck wants to instantly know the total of every order without recalculating, it could write that total directly on the index card – that's a 'projection' – but it takes extra writing time. And if the truck changes the order's total later, it has to update both the main book and the index card. That extra work is the trade-off.
That is exactly how DynamoDB works: one main table with a primary key, and you can add indexes to query data by other fields, but every index costs you write time and storage space.
Amazon DynamoDB is a fully managed NoSQL database service offered by Amazon Web Services (AWS). Let us break that down.
Fully managed means AWS handles all the hardware, software, patching, backups, and scaling for you. You do not need to install anything, upgrade anything, or worry about the server crashing. NoSQL (Not Only SQL) means it does not use the traditional table-and-join structure of a relational database like MySQL or PostgreSQL. Instead, it stores data as items (like rows) in tables, and each item can have a different set of attributes (like columns). This is flexible because you can add new fields to one item without affecting any other item.
Every table in DynamoDB must have a primary key. The primary key is a unique identifier for each item in the table. For example, if you are storing user accounts, the primary key could be 'UserID'. When you ask DynamoDB to fetch an item by its primary key, it is extremely fast because the database uses that key to locate the data instantly. This is called a point lookup. If you do not provide the primary key, DynamoDB has to scan the entire table – that is, look at every single item – to find what you need. Scans are slow and expensive in terms of the read capacity they consume.
There are two types of primary keys:
Simple primary key: a single attribute (like UserID) that uniquely identifies each item.
Composite primary key: two attributes combined – a partition key and a sort key. The partition key is used to decide which physical storage partition the item goes into. The sort key is used to order items within that partition. Together, they uniquely identify an item.
Now, what if you want to look up items by a different attribute, such as 'Email' or 'OrderDate'? That is where indexes come in. An index is a separate data structure that copies some or all of your data and reorganises it by a different key.
There are two types of indexes in DynamoDB:
Global Secondary Index (GSI): has a different partition key and/or sort key from the main table. You can create it after the table is created, and it spans the entire table. Each GSI has its own provisioned read and write capacity.
Local Secondary Index (LSI): shares the same partition key as the main table but uses a different sort key. You can only create an LSI when you first create the table, and it uses the table's read/write capacity.
When you query an index, you are not scanning the main table. Instead, DynamoDB reads directly from the index's prefabricated copy of the data. This is much faster. However, indexes have a cost: every time you write or update an item in the main table, DynamoDB must also update every index that includes that item. This consumes more write capacity and storage.
You can also choose which attributes are 'projected' (copied) into the index. The choices are: ALL (copy every attribute), KEYS_ONLY (copy only the primary key attributes), or INCLUDE (copy only a specific list of attributes). Projecting more attributes makes queries faster because you can get the answer directly from the index without going back to the main table, but it uses more storage.
Understanding when to use a scan versus a query is crucial. A query is always more efficient than a scan because a query uses the primary key or an index key to narrow down the search. A scan reads every item in the table and then filters out the ones you do not want. You should always prefer a query if possible. The exam loves to test this distinction.
Finally, DynamoDB has a concept called 'eventually consistent reads' and 'strongly consistent reads'. Eventually consistent reads are cheaper and slightly faster because they can return data that is a tiny bit out of date (less than one second). Strongly consistent reads always return the latest data but cost more. For most applications, eventual consistency is fine.
Identify access patterns
Before creating any DynamoDB table, list every query your application will make. For example: 'Fetch user by UserID', 'Fetch all orders for a customer', 'Fetch orders by date'. This determines your primary key and index design.
Choose a primary key
Select a simple or composite primary key that matches your most frequent point-lookup query. For example, if you always look up orders by OrderID, use that as a simple primary key. If you need to group by UserID and order by OrderDate, use a composite key with UserID as partition key and OrderDate as sort key.
Design indexes for secondary queries
For each non-primary-key access pattern, decide if you need a GSI or LSI. If the query uses a different partition key, use a GSI. If it uses the same partition key but a different sort key, you could use an LSI (if created at table creation) or a GSI (if added later). Choose projection type (ALL, KEYS_ONLY, or INCLUDE) based on how much data you need from the index.
Create the table and indexes
Using the AWS Management Console, CLI, or SDK, create the table with the primary key you chose. If you need an LSI, you must add it during this step. You can add GSIs now or later. Set provisioned read/write capacity or use on-demand mode for unknown traffic.
Write application code using Query
In your application code, use the DynamoDB Query API (not Scan) to retrieve data. Always specify the table name or index name, and provide the key attribute values. Use KeyConditionExpression to filter by partition key and optionally sort key. Avoid Scan for any production query that can be replaced by a Query.
Monitor and optimise
After deployment, use Amazon CloudWatch to monitor ConsumedReadCapacityUnits and ConsumedWriteCapacityUnits for both the table and each index. If you see throttling or high latency, consider adding a GSI with a better key distribution or increasing provisioned capacity. Adjust projections to reduce storage if needed.
Imagine you are the database engineer for TicketySplit, a startup that sells event tickets online. The company stores every ticket sale in a DynamoDB table called 'Orders'. Each order has: OrderID (primary key), CustomerID, EventName, EventDate, TicketQuantity, TotalPrice, and OrderStatus.
When a customer logs into their account, they want to see all of their past orders. To do this, you would need to search by CustomerID, not by OrderID. But the table's primary key is OrderID. If you scanned the entire table for all orders where CustomerID equals 'abc123', it would be slow and expensive as the table grows to millions of orders.
So what does the IT professional do? They create a Global Secondary Index (GSI) with CustomerID as the partition key. Now when someone asks 'show me all orders for customer abc123', DynamoDB uses the GSI to instantly find those orders. The developer writes a Query call to DynamoDB specifying the GSI name and the CustomerID value. That query returns all matching items almost instantly, no scan needed.
But now there is another requirement: the marketing team wants to generate a report of all orders placed on a specific date. You could create another GSI with EventDate as the partition key. However, if dates are not unique (thousands of orders on the same day), you might also include a sort key like OrderTime to order them. Alternatively, you could create a GSI with a composite partition key combining EventDate and EventName.
Here are the steps an IT professional would take:
Analyse the access patterns: what queries will the application make most often?
Choose a primary key that matches the most common point lookup (e.g., OrderID).
Design GSIs for other frequent query patterns (e.g., by CustomerID, by EventDate).
Decide on projection: for the CustomerID GSI, project only CustomerID and OrderStatus (not the full order) to save storage, because you will still need to fetch full order details from the main table using the primary key that the GSI returns.
Set the read capacity: estimate how many reads per second each query will need.
Write application code that uses Query (not Scan) and specifies the index name.
Monitor performance with CloudWatch metrics, like ConsumedReadCapacityUnits.
If the original primary key design turns out to be wrong, the IT professional can add a new GSI at any time without downtime. However, they cannot add an LSI later – that must be defined at table creation. This is a key difference tested on the exam.
The DVA-C02 exam tests your ability to design DynamoDB tables and choose between query, scan, and index types. Here is exactly what you need to know.
The most common question type is: 'Which DynamoDB operation is most efficient for this scenario?' The correct answer is almost always 'Query' if the question mentions filtering by a specific key. The trap is when they describe a scenario where the key attribute is something the table does not index – then you need a GSI or an LSI.
Specifically, exam questions love the following:
The difference between a primary key (simple vs composite) and the two types of indexes (GSI vs LSI).
The fact that LSIs cannot be added after table creation – only GSIs can be added later.
The concept of eventual versus strong consistency and when to use each.
How projections affect cost and performance (ALL vs KEYS_ONLY vs INCLUDE).
Common traps:
Scanning is always the wrong answer if there is any other option that uses an index. They will set a scenario where the query key is not the primary key, and ask you to choose between a scan and a query with a GSI. The correct answer is always 'query with a GSI'.
They will ask about 'eventually consistent reads' – the trap is that some beginners think it means 'the data is lost' or it takes minutes to update. In reality, it takes less than a second, and it is the default.
They might ask about 'hot partitions' – if your primary key is not well-distributed (e.g., a date like today's date, so all writes go to one partition), you will get throttling. The solution is to add a random suffix or use a composite key.
Key definitions to memorise:
Partition key: used to distribute data across physical storage.
Sort key: orders items within a partition.
GSI: index with a different partition key; can be created anytime.
LSI: index with same partition key, different sort key; must be created at table creation.
Eventually consistent read: default, cheaper, may return stale data.
Strongly consistent read: always returns latest data, costs more.
You will also see questions about Write Capacity Units (WCU) and Read Capacity Units (RCU). One write unit = one write per second for an item up to 1 KB. One read unit = one strongly consistent read per second for an item up to 4 KB, or two eventually consistent reads per second for the same size. Knowing these numbers is not always required, but understanding that GSIs consume their own capacity is important.
Finally, exam questions often present a 'legacy relational database' design (a normalised schema with many tables) and ask you to convert it to a single DynamoDB table with appropriate indexes. The correct answer usually uses a single table with a composite primary key (like CustomerID + OrderID) and multiple GSIs for different access patterns.
Every DynamoDB table must have a primary key, which can be simple (one attribute) or composite (partition key plus sort key).
A query operation is always more efficient than a scan because it uses an index or primary key to locate data directly.
Global Secondary Indexes (GSIs) can be created at any time and have a different partition key from the main table.
Local Secondary Indexes (LSIs) must be defined at table creation and share the same partition key as the main table.
Eventually consistent reads are the default and cost half as much as strongly consistent reads, with a delay of less than one second.
Every GSI consumes its own read and write capacity, and if the GSI's write capacity is too low, it can throttle writes to the main table.
These come up on the exam all the time. Here's how to tell them apart.
Global Secondary Index (GSI)
Can be created at any time, even after table creation
Has a different partition key from the main table
Has its own provisioned read and write capacity
Local Secondary Index (LSI)
Must be defined when the table is first created
Shares the same partition key as the main table
Uses the main table's read and write capacity
Query Operation
Uses a primary key or index key to retrieve specific items quickly
Always more efficient than scan for filtered lookups
Can return a limited set of items based on key conditions
Scan Operation
Reads every item in the entire table
Expensive and slow for large tables
Used when you need all items or when no index exists for the filter criteria
Eventually Consistent Read
Default read mode in DynamoDB
May return slightly stale data (delay < 1 second)
Consumes half the read capacity of strong consistency
Strongly Consistent Read
Must be explicitly requested
Always returns the latest written data
Consumes twice the read capacity of eventual consistency
Simple Primary Key
Consists of a single attribute (e.g., UserID)
Must be unique across the table
Best for point lookups by a single identifier
Composite Primary Key
Consists of a partition key and a sort key
Uniqueness is based on the combination of both keys
Allows grouping of items within a partition and sorting them
Mistake
DynamoDB is just like a regular SQL table, and I can use joins between tables.
Correct
DynamoDB is a NoSQL database that does not support joins. You should denormalise data and store related information together in one table or use application-level logic to combine data.
Beginners are familiar with relational databases from university courses or small projects, so they expect every database to support SQL joins.
Mistake
I can add a Local Secondary Index to any table at any time.
Correct
You can only define Local Secondary Indexes (LSIs) when you create the table. Once the table exists, you cannot add an LSI later. You can only add Global Secondary Indexes after creation.
The word 'local' does not hint at the creation-time restriction, and beginners confuse LSIs with GSIs.
Mistake
Making a query with 'ScanIndexForward = false' means I am scanning the index, which is expensive.
Correct
ScanIndexForward = false simply returns items in descending sort order. It is still a query operation, not a scan. It uses the same efficient index lookup and is not expensive like a table scan.
The word 'scan' in the parameter name misleads beginners into thinking it is a costly operation.
Mistake
If I have a Global Secondary Index, I never need to worry about the main table's read/write capacity.
Correct
Global Secondary Indexes have their own provisioned read and write capacity. If the main table has high write traffic but the GSI has low write capacity, writes to the main table can be throttled because the GSI cannot keep up.
The term 'global' makes beginners think the index is independent and does not affect the main table.
Mistake
Strongly consistent reads are always better because they give you the latest data.
Correct
Strongly consistent reads are more expensive and use more read capacity. In most applications, eventually consistent reads are sufficient because the delay is less than a second, and they are half the cost.
Beginners often overvalue consistency because they think 'always latest' is critical for every use case, without considering cost-performance trade-offs.
Mistake
Queries are always faster than scans, so I should always use a query even if I need all items in the table.
Correct
If you need to return every item in the table (e.g., for a report), a scan is the only option. A query requires a specific key value. Using a query with a wildcard is not possible in DynamoDB.
The belief that queries are always better leads beginners to try to force queries where they are not applicable, causing confusion when they cannot get all items.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
A Global Secondary Index (GSI) has a different partition key from the main table and can be created at any time. A Local Secondary Index (LSI) shares the same partition key as the main table but has a different sort key, and it can only be created when the table is first created.
Yes, you can have multiple tables, but DynamoDB does not support joins. Instead of normalising data across tables, you typically store related data together in one table (denormalisation) and use indexes to access it in different ways.
DynamoDB does not have a direct SELECT * equivalent. To get all items in a table, you must use a Scan operation, which reads every item. This is expensive and slow for large tables. For filtered retrieval, use a Query with a primary key or index key.
If you use a simple primary key, it must be unique. If you use a composite key (partition key + sort key), the combination of both must be unique. If you insert a new item with the same primary key as an existing item, the existing item is overwritten.
It means that when you read data, you might not see the very latest write if that write happened just a split second ago. The delay is typically under one second. This is the default read mode and uses half the read capacity of a strongly consistent read.
No, you cannot alter the primary key of an existing table. You would need to create a new table with the desired primary key and migrate the data using tools like AWS Data Pipeline or a custom script.
Yes, set the 'ScanIndexForward' parameter to 'false' in your Query request. This returns items in descending order based on the sort key. The name is confusing – it is still a Query operation, not a scan.
You've just covered Amazon DynamoDB: Tables, Queries, and Indexes — now see how well it sticks with free DVA-C02 practice questions. Full explanations included, no account needed.
Done with this chapter?