Home/Learn/MySQL/Sharding Concepts

Sharding Concepts

Advanced
Scaling

Horizontal sharding splits data across multiple DB instances by a shard key (range, hash, directory); application or middleware (Vitess, ProxySQL) routes queries to the correct shard.

Overview

Sharding is horizontal partitioning across multiple independent database instances (shards), each owning a subset of the data. Unlike MySQL table partitioning (which stays on one server), sharding scales write throughput by distributing load across machines. The shard key determines data placement. Common strategies are range-based (e.g. user IDs 1-1M on shard 1), hash-based (user_id % N), and directory-based (lookup table maps key → shard). Cross-shard queries, distributed transactions, and resharding are the primary challenges. Tools like Vitess (YouTube) and ProxySQL provide transparent sharding middleware.

Shard Key Selection

The shard key is the most important sharding decision. It must distribute writes evenly, avoid hot spots, and ideally be included in most queries to prevent cross-shard scatter-gather operations.

Java + SQL — shard key strategies
-- Good shard keys:
-- ✓ user_id (for user-centric workloads — queries are per-user)
-- ✓ tenant_id (SaaS multi-tenancy — each tenant to one shard)
-- ✓ order_id with hash (uniform write distribution)

-- Bad shard keys:
-- ✗ created_at (sequential inserts → all writes to last shard — hot spot)
-- ✗ status ('pending'/'shipped' — low cardinality → uneven distribution)
-- ✗ country (most traffic from US/IN → imbalanced shards)

-- Hash-based routing example (application layer)
public class ShardRouter {
    private static final int NUM_SHARDS = 8;

    public int getShardId(long userId) {
        return (int) (userId % NUM_SHARDS);
    }

    public DataSource getDataSource(long userId) {
        int shard = getShardId(userId);
        return dataSourceMap.get("shard-" + shard);
    }
}

-- Directory-based routing (lookup table on a config DB)
-- SELECT shard_id FROM shard_directory WHERE tenant_id = ?

Vitess for Transparent Sharding

Vitess is a MySQL-compatible sharding middleware used at YouTube, Slack, and PlanetScale. It handles shard routing, connection pooling, schema changes, and resharding transparently, so applications connect to Vitess as if it were a single MySQL server.

JSON + SQL — Vitess VSchema and routing
# Vitess VSchema — define sharding rules
{
  "sharded": true,
  "vindexes": {
    "hash": {
      "type": "hash"     // hash vindex on the shard key
    }
  },
  "tables": {
    "orders": {
      "columnVindexes": [
        { "column": "user_id", "name": "hash" }
      ]
    }
  }
}

# Application uses standard MySQL driver — Vitess routes transparently
mysql -h vtgate-host -P 3306 -u app -p shop

-- This query is automatically routed to the correct shard:
SELECT * FROM orders WHERE user_id = 12345;

-- This scatter-gather (no shard key) fans out to all shards:
SELECT COUNT(*) FROM orders WHERE status = 'PENDING';
-- Vitess aggregates results — expensive, avoid for hot paths

Cross-Shard Challenges

Cross-shard JOINs, distributed transactions (2PC), and global unique IDs are the main pain points. Use application-layer aggregation, eventual consistency (saga pattern), and distributed ID generators (Snowflake, UUID v7) to address them.

Java + SQL — cross-shard patterns
-- Cross-shard JOIN — avoid in application hot paths
-- Instead of: SELECT o.*, c.email FROM orders o JOIN customers c ON o.customer_id = c.id
-- ✓ Denormalise: store email inside orders row (accept duplication)
-- ✓ Or: fetch orders, then batch-fetch customers by ID in application code

-- Global unique ID — Snowflake-style (64-bit)
// 41 bits timestamp | 10 bits machine ID | 12 bits sequence
public class SnowflakeIdGenerator {
    private final long machineId;
    private long lastTimestamp = -1L;
    private long sequence = 0L;

    public synchronized long nextId() {
        long ts = System.currentTimeMillis();
        if (ts == lastTimestamp) {
            sequence = (sequence + 1) & 0xFFF;  // 12-bit max
            if (sequence == 0) ts = waitNextMs(ts);
        } else { sequence = 0; }
        lastTimestamp = ts;
        return ((ts - EPOCH) << 22) | (machineId << 12) | sequence;
    }
}

Key Points to Remember

  • 1Sharding splits data across multiple DB instances for horizontal write scalability.
  • 2Shard key must have high cardinality and align with the dominant query pattern.
  • 3Hash sharding distributes evenly; range sharding enables efficient range scans.
  • 4Cross-shard queries require scatter-gather — expensive; design to avoid them.
  • 5Use Snowflake IDs or UUID v7 for globally unique IDs across shards.
  • 6Vitess and ProxySQL provide transparent sharding middleware for MySQL.

Interview Questions

Sign in to ask Aria
1

What is the difference between MySQL partitioning and sharding?

MediumAmazon
2

How do you choose a good shard key?

HardUber
3

How do you handle cross-shard JOINs in a sharded database?

HardLinkedIn
4

What is a hot shard and how do you prevent it?

MediumFlipkart
5

How would you generate globally unique IDs across multiple database shards?

HardTwitter

Ask Aria about Sharding Concepts

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…