When should you use a Global Secondary Index versus a Local Secondary Index?
A clear decision guide for choosing a DynamoDB GSI vs LSI based on partition key, consistency, throughput and timing, with query code examples.
Expected Interview Answer
Use a Global Secondary Index (GSI) when you need to query on a completely different partition key or need independent throughput; use a Local Secondary Index (LSI) when you keep the same partition key but need an alternate sort order with strongly consistent reads.
Choose a GSI for cross-cutting access patterns, such as querying by status, email, or any attribute unrelated to the base partition key, because a GSI defines its own keys, scales independently, and can be added to a live table. Choose an LSI when your queries stay within one partition key's item collection but need a second sort dimension and strong consistency, accepting that LSIs must be defined at table creation and count against the 10 GB per-partition-key limit. In practice most modern designs favour GSIs for their flexibility and the fact that they can be created later; LSIs are reserved for the narrower case where strong consistency on an alternate sort key genuinely matters.
- GSI: query by any attribute with its own scalable throughput
- GSI: create or remove on a live table without downtime
- LSI: strongly consistent reads on a second sort key
- LSI: no extra throughput provisioning (shares the table)
- Clear decision rule reduces over-indexing and cost
AI Mentor Explanation
Deciding between the two indexes is like choosing your reference tool. If you still want a single batter's innings but re-sorted by boundaries and need it dead accurate right now, an appendix inside that batter's page (LSI) works. If instead you want to look players up by team across the whole season with its own dedicated staff, you build a separate cross-season directory (GSI).
Step-by-Step Explanation
Step 1
Check the partition key
If the new query keeps the table's partition key, an LSI is possible; if it needs a different one, you must use a GSI.
Step 2
Assess consistency needs
Require strongly consistent reads on the alternate key? Only an LSI can provide them; GSIs are eventual.
Step 3
Consider timing
Table already exists? You can only add a GSI, since LSIs must be defined at creation.
Step 4
Weigh throughput isolation
Need independent, separately scalable capacity? Choose a GSI; an LSI shares base-table throughput.
Step 5
Mind the item collection limit
LSIs count toward the 10 GB per-partition-key limit; large collections favour a GSI.
Step 6
Default to flexibility
When both fit and strong consistency is not required, prefer a GSI for its flexibility and later creation.
What Interviewer Expects
- A crisp decision rule based on partition key and consistency
- Awareness that LSIs must exist at table creation, GSIs anytime
- Understanding of throughput isolation with GSIs
- Knowledge of the 10 GB item collection limit for LSIs
- A concrete example access pattern for each choice
Common Mistakes
- Reaching for an LSI when the query needs a different partition key
- Assuming a GSI can deliver strongly consistent reads
- Trying to add an LSI to an existing table
- Over-indexing with many GSIs and inflating write cost
- Ignoring that a GSI's writes consume separate write capacity
Best Answer (HR Friendly)
“Use a Global Secondary Index when you want to search by a totally different field or need separate capacity, and it can be added anytime. Use a Local Secondary Index when you keep the same main key but need a different sort order with always-accurate reads, deciding this upfront when you create the table.”
Code Example
import boto3
from boto3.dynamodb.conditions import Key
table = boto3.resource('dynamodb').Table('Orders')
# GSI 'byStatus' fetches every PENDING order regardless of customer.
# GSI reads are eventually consistent, so ConsistentRead is not allowed.
resp = table.query(
IndexName='byStatus',
KeyConditionExpression=Key('status').eq('PENDING'),
)
print(resp['Items'])
# LSI 'byOrderDate' stays within one customer but sorts by date,
# and CAN use strongly consistent reads.
resp2 = table.query(
IndexName='byOrderDate',
KeyConditionExpression=Key('customerId').eq('C-100'),
ConsistentRead=True,
)
print(resp2['Items'])Follow-up Questions
- Give an access pattern that can only be served by a GSI.
- Why might over-provisioning GSIs increase your write costs?
- How does the 10 GB item collection limit influence LSI use?
- Can you migrate an LSI-only design to GSIs, and how?
- How does eventual consistency on a GSI affect read-after-write logic?
MCQ Practice
1. You must query by an attribute that is NOT the table's partition key. Which index do you need?
Only a GSI can define a new partition key, so cross-cutting queries on non-key attributes require a GSI.
2. Your query keeps the same partition key but needs strongly consistent reads on a new sort order. Best choice?
An LSI shares the partition key and uniquely supports strongly consistent reads on an alternate sort key.
3. The table already exists in production. Which index can you still add?
LSIs must be created at table creation; GSIs can be added to or removed from a live table anytime.
Flash Cards
Need a different partition key? — Use a GSI, only it can define a new partition key.
Need strong consistency on an alternate sort key? — Use an LSI, GSIs are eventually consistent.
Table already live? — You can only add a GSI; LSIs must exist from creation.
Need isolated, scalable throughput? — Use a GSI, it has its own capacity; an LSI shares the table's.
Default when both fit? — Prefer a GSI for flexibility and the ability to create it later.