In Module 3, you learned about DynamoDB table design and primary keys. In this module, we'll dive deeper into DynamoDB by exploring secondary indexes, which provide additional ways to query your data beyond what's possible with just the primary key.
Secondary indexes in DynamoDB allow you to query the data in your table using an alternate key, in addition to queries against the primary key. DynamoDB supports two types of secondary indexes:
In this module, we'll focus primarily on Global Secondary Indexes (GSIs) as they are more flexible and commonly used.
A Global Secondary Index (GSI) is a data structure that contains a subset of attributes from a table, along with an alternate key to support Query operations. The index is "global" because queries on the index can span all of the data in the base table, across all partitions.
You can think of a GSI as a separate table that is automatically maintained by DynamoDB. When you add, update, or delete an item in the base table, DynamoDB automatically propagates these changes to any GSIs on that table.
GSIs provide several advantages:
GSIs are particularly useful when:
When creating a GSI, you must specify which attributes from the base table should be "projected" (copied) into the index. You have three projection options:
Choosing the right projection type involves balancing storage costs and query performance:
One powerful technique with GSIs is "overloading" them to support multiple access patterns. This involves using a GSI for multiple purposes by carefully designing your attribute values.
For example, consider a social media application where you need to:
You could create a GSI with:
GSI_PK
(which could be either "USER#username" or "HASHTAG#tag")CreatedAt
(timestamp when the item was created)This allows you to query for all posts by a user or all posts with a specific hashtag using the same index.
When you have a "hot" partition key (one that receives a disproportionate amount of traffic), you can use write sharding to distribute the load across multiple partitions. This involves adding a random suffix to your partition key to spread the writes across partitions.
Here are some common patterns for using GSIs effectively:
In your project, you'll use AWS CloudFormation to create and configure GSIs. Here's an example of how to define a GSI in a CloudFormation template:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"MyTable": {
"Type": "AWS::DynamoDB::Table",
"Properties": {
"TableName": "MyTable",
"BillingMode": "PAY_PER_REQUEST",
"AttributeDefinitions": [
{
"AttributeName": "PK",
"AttributeType": "S"
},
{
"AttributeName": "SK",
"AttributeType": "S"
},
{
"AttributeName": "GSI1PK",
"AttributeType": "S"
},
{
"AttributeName": "GSI1SK",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "PK",
"KeyType": "HASH"
},
{
"AttributeName": "SK",
"KeyType": "RANGE"
}
],
"GlobalSecondaryIndexes": [
{
"IndexName": "GSI1",
"KeySchema": [
{
"AttributeName": "GSI1PK",
"KeyType": "HASH"
},
{
"AttributeName": "GSI1SK",
"KeyType": "RANGE"
}
],
"Projection": {
"ProjectionType": "ALL"
}
}
]
}
}
}
}
In this example, we've defined a table with a composite primary key (PK and SK) and a GSI with its own composite key (GSI1PK and GSI1SK). The GSI projects all attributes from the base table.
To query a GSI in Java, you use the DynamoDB query()
operation with the index name specified. Here's an example:
QueryRequest queryRequest = new QueryRequest()
.withTableName("MyTable")
.withIndexName("GSI1")
.withKeyConditionExpression("GSI1PK = :pk")
.withExpressionAttributeValues(Map.of(":pk", new AttributeValue("USER#johndoe")));
QueryResult result = dynamoDbClient.query(queryRequest);
List<Map<String, AttributeValue>> items = result.getItems();
This query retrieves all items from the GSI1 index where the GSI1PK is "USER#johndoe". The query will return all attributes that were projected into the index.
When querying GSIs, keep these best practices in mind:
Learn about the basics of Global Secondary Indexes in DynamoDB.
Learn advanced techniques for working with GSIs in DynamoDB.
Learn how to optimize the performance of your GSIs.
In the guided project for this module, you'll apply what you've learned about DynamoDB Index Design to enhance your Learn and Be Curious project with GSIs.
This project will guide you through designing and implementing GSIs for your project's DynamoDB tables to support additional access patterns.
Update the tables section of your design document to include GSIs that support your access patterns.
AWS documentation on DynamoDB secondary indexes.
AWS workshop on advanced DynamoDB index design patterns.
Article explaining how to implement GSI write sharding in DynamoDB.