gotchajavascriptMajor
DynamoDB GSI hot partition causes throttling on write-heavy workloads
Viewed 0 times
GSI hot partitionwrite shardinglow cardinalityProvisionedThroughputExceededExceptionshard suffixfan out query
Error Messages
Problem
A Global Secondary Index (GSI) on a low-cardinality attribute (e.g., status='active') creates a hot partition when many items have the same GSI key value, causing write throttling even when the base table has spare capacity.
Solution
Add a random suffix (write sharding) to the GSI key to distribute writes across multiple partitions. At read time, fan out queries across all shard keys and merge results.
// Write: add shard suffix
const shard = Math.floor(Math.random() * 10);
const item = {
PK: `USER#${userId}`,
SK: 'PROFILE',
status_shard: `active#${shard}`, // GSI key
};
// Read: query all shards
const results = await Promise.all(
Array.from({ length: 10 }, (_, i) =>
dynamo.send(new QueryCommand({
TableName: 'AppTable',
IndexName: 'status-index',
KeyConditionExpression: 'status_shard = :s',
ExpressionAttributeValues: { ':s': `active#${i}` }
}))
)
);Why
DynamoDB distributes data across partitions based on the hash of the partition key. When many items share the same GSI key, all writes land on the same partition, exhausting its 1000 WCU/s limit regardless of total provisioned capacity.
Gotchas
- GSI capacity is provisioned separately from the base table — a GSI can throttle even if the base table has spare WCUs
- On-demand capacity mode does not eliminate hot partitions — it only adjusts total throughput, not per-partition distribution
- Sparse GSIs (only items with the attribute are projected) are efficient for selective queries — use them for flag attributes
- GSI propagation is asynchronous — newly written items may not appear in GSI queries immediately
Code Snippets
Write sharding pattern for hot GSI partitions
// Write sharding for low-cardinality GSI key
const SHARD_COUNT = 10;
const shardedKey = (baseValue) => `${baseValue}#${Math.floor(Math.random() * SHARD_COUNT)}`;
// Fan-out read across shards
async function queryAllShards(baseValue) {
const queries = Array.from({ length: SHARD_COUNT }, (_, i) =>
dynamo.send(new QueryCommand({
TableName: 'AppTable',
IndexName: 'MyGSI',
KeyConditionExpression: 'gsiKey = :k',
ExpressionAttributeValues: { ':k': `${baseValue}#${i}` },
}))
);
const results = await Promise.all(queries);
return results.flatMap(r => r.Items);
}Context
Using DynamoDB GSIs on attributes with a small number of distinct values under high write load
Revisions (0)
No revisions yet.