Home/Learn/System Design/Database Sharding
system designadvanced

Database Sharding Explained

Database sharding splits one large database into smaller, faster parts called shards. Each shard holds a subset of the data and operates independently. Sharding is the nuclear option : use it when vertical scaling, read replicas, and caching are not enough.

1. When to Shard

graph TD
    Start["Single DB hitting limits"]
    Step1{"Vertical scaling
enough?"}
    Step2{"Read replicas
enough?"}
    Step3{"Caching
enough?"}
    Shard["Time to shard"]
    Done["Stick with current setup"]

    Start --> Step1
    Step1 -->|"Yes"| Done
    Step1 -->|"No, writes bottlenecked"| Step2
    Step2 -->|"Yes"| Done
    Step2 -->|"No, writes still bottlenecked"| Step3
    Step3 -->|"Yes"| Done
    Step3 -->|"No"| Shard

    style Start fill:#FFF3CD,stroke:#FFC107
    style Shard fill:#D97A2B,stroke:#B86418,color:#fff
    style Done fill:#D4EDDA,stroke:#28A745
  • Write throughput exceeds what a single server can handle (tens of thousands of writes/sec)
  • Read replicas help with read-heavy workloads, but writes are still bottlenecked on a single primary
  • Vertical scaling (bigger hardware) is too expensive or has hit its ceiling
  • Data size exceeds a single server's storage capacity

2. Choosing a Shard Key

The shard key determines which shard a record is stored on. This is the most critical decision : a bad shard key creates hot spots that negate the benefits of sharding.

graph TD
    ShardKey["Shard Key Selection"]
    UserID["User ID
All data for one user on same shard
Good for user-centric queries
Risk: hot spots for power users"]
    Geo["Geographic Region
Data co-located with users
Reduces latency
Risk: uneven distribution"]
    Timestamp["Timestamp
Time-series data naturally shards
Good for analytics
Risk: current time = hot shard"]

    ShardKey --> UserID
    ShardKey --> Geo
    ShardKey --> Timestamp

    style ShardKey fill:#D97A2B,stroke:#B86418,color:#fff
    style UserID fill:#FAF6EE,stroke:#E8DFC8
    style Geo fill:#FAF6EE,stroke:#E8DFC8
    style Timestamp fill:#FAF6EE,stroke:#E8DFC8

3. Sharding Strategies

Hash-Based Sharding

Hash the shard key: shard = hash(key) % numShards. Even distribution, but adding/removing shards requires rehashing all keys.

graph LR
    Key["user_id = 12345"]
    Hash["hash(12345) = 78901234"]
    Mod["78901234 % 4 = 2"]
    Shard["Shard 2"]

    Key --> Hash --> Mod --> Shard

    style Key fill:#FAF6EE,stroke:#E8DFC8
    style Hash fill:#D97A2B,stroke:#B86418,color:#fff
    style Mod fill:#FAF6EE,stroke:#E8DFC8
    style Shard fill:#D4EDDA,stroke:#28A745

Range-Based Sharding

Assign key ranges to shards: Shard 0 gets keys 0-999, Shard 1 gets 1000-1999. Simple but can create hot spots if access patterns are skewed.

Consistent Hashing

Maps keys and shards onto a hash ring. When a shard is added/removed, only neighboring keys move. Minimizes data migration. Read our consistent hashing tutorial for details.

4. Architecture: Shard Router

graph LR
    Client["Client"]
    Router["Shard Router
(determines target shard)"]
    S1["Shard 1
(users 0-999K)"]
    S2["Shard 2
(users 1M-1.9M)"]
    S3["Shard 3
(users 2M-2.9M)"]
    S4["Shard 4
(users 3M+)"]

    Client --> Router
    Router --> S1
    Router --> S2
    Router --> S3
    Router --> S4

    style Client fill:#FAF6EE,stroke:#E8DFC8
    style Router fill:#D97A2B,stroke:#B86418,color:#fff
    style S1 fill:#FAF6EE,stroke:#E8DFC8
    style S2 fill:#FAF6EE,stroke:#E8DFC8
    style S3 fill:#FAF6EE,stroke:#E8DFC8
    style S4 fill:#FAF6EE,stroke:#E8DFC8

5. Challenges of Sharding

Cross-Shard Queries

SQL JOINs across shards are expensive. You must query multiple shards and merge results in the application layer. Denormalize data to avoid joins.

Distributed Transactions

ACID transactions across shards require two-phase commit (2PC), which is slow and complex. Prefer eventual consistency where possible.

Rebalancing

When a new shard is added, existing data must be redistributed. This can cause downtime if not handled carefully. Use consistent hashing to minimize migration.

Global Unique IDs

Auto-increment IDs collide across shards. Use UUIDs, Snowflake IDs, or a centralized ID generator.

6. Common Interview Mistakes

  • Sharding too early: Try vertical scaling, read replicas, and caching first. Sharding adds massive complexity.
  • Poor shard key selection: An uneven shard key creates hot spots that negate the benefits of sharding.
  • Ignoring cross-shard queries: Design your data model so most queries hit a single shard.
  • Not planning for growth: Choose a shard key and strategy that supports 10x your current data size.
  • Forgetting about monitoring: Shard health, query latency per shard, and data distribution must be tracked.

7. Summary

StrategyProsCons
Hash-basedEven distributionAdding shards rehashes all keys
Range-basedSimple, range queries efficientHot spots on current range
Consistent hashingMinimal data migrationComplex implementation

Put it into practice

Ready to practice?

Start a mock interview with AI interviewer Alex. Get instant hiring signal.

Start a Mock Interview →