Three genuinely different scaling techniques often confused for one another — shard key selection, table partitioning within one database, read replicas, replication lag, and failover.
Published September 23, 2026
Three distinct techniques that get conflated constantly — each solves a different scaling problem, and confusing them in an interview is a fast way to lose credibility on a database-scaling question.
users 1-1M → Database Shard A
users 1M-2M → Database Shard B
users 2M-3M → Database Shard C
Rows are split across multiple independent database instances by a shard key — each shard is a fully separate database, potentially on separate hardware, with no single database holding the entire dataset. This is the mechanism that lets total data size and write throughput scale past what any single database server could handle, at the cost of real complexity: cross-shard queries (joining data that lives on different shards) become expensive or require application-level aggregation rather than a single SQL query.
A poorly chosen shard key concentrates traffic on one shard — sharding by signup_date in a growing product means the newest (most active) shard gets disproportionately more write traffic than older ones, creating a hot shard while others sit comparatively idle. The range-based vs hash-based tradeoff: range-based sharding (contiguous key ranges per shard) makes range queries efficient but risks exactly this hot-shard problem if writes cluster in one range; hash-based sharding (a hash function distributes keys pseudo-randomly across shards) spreads write load evenly but makes range queries expensive (a range query now has to hit every shard, since consecutive keys are scattered across all of them).
CREATE TABLE orders (
id BIGINT, created_at DATE, ...
) PARTITION BY RANGE (created_at);
CREATE TABLE orders_2024 PARTITION OF orders FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
CREATE TABLE orders_2025 PARTITION OF orders FOR VALUES FROM ('2025-01-01') TO ('2026-01-01');
This is the detail most commonly confused with sharding: partitioning splits a table into smaller physical pieces (range, list, or hash partitioning) within a single database instance — it's a storage/query-optimization technique (queries filtering by the partition key can skip entire partitions entirely, and maintenance operations like archiving old data become cheaper), not a horizontal-scale-past-one-machine technique. Sharding solves "this dataset is too big for one database server"; partitioning solves "this table is unwieldy to manage/query efficiently even though it still fits on one server." They're frequently combined (each shard's own large tables partitioned internally), but they answer different questions.
[Primary] → (async replication) → [Replica 1] → serves read traffic
→ [Replica 2] → serves read traffic
All writes go to the primary; reads can be distributed across one or more replicas that receive an asynchronous copy of the primary's changes. This scales read throughput independently of write throughput — a read-heavy workload (the common case for most applications) benefits enormously without needing sharding's write-scaling complexity at all.
Because replication is asynchronous, a replica can lag behind the primary by some amount (milliseconds to, under heavy load, much longer) — a write committed to the primary might not be visible on a replica yet. This breaks a naive "write then immediately read your own write" flow if the read happens to hit a lagging replica: the user's own just-made change appears to not have happened. Common mitigations: read-your-own-writes routing (route a user's reads to the primary, or to the specific replica known to have caught up, immediately after that user's own write), or accepting eventual consistency for reads that aren't immediately user-visible.
When the primary fails, one replica is promoted to become the new primary — during this transition, there's typically a brief unavailability window for writes (the old primary is down, the new primary isn't fully promoted and receiving traffic yet), even though reads from healthy replicas may continue uninterrupted throughout. How brief that window is depends heavily on whether failover is automatic (a monitoring system detects failure and triggers promotion) or manual (an operator intervenes) — automatic failover trades a small risk of an unnecessary failover (triggered by a false-positive health check) for a much shorter actual downtime window.
Q: Can you shard AND replicate at the same time? A: Yes, and production systems at real scale routinely do both — each shard is itself a primary with its own set of read replicas, combining horizontal write/storage scaling (sharding) with read-throughput scaling and failover resilience (replication) at each individual shard.
Q: Why would range partitioning by date be a good choice for partitioning but a risky choice for sharding? A: Within a single database, range-partitioning by date is excellent for a common access pattern (most queries touch recent data, easy archival of old partitions) without the hot-shard concern, because all partitions still share the same underlying server's resources. As a sharding key across separate database servers, the same date-based split concentrates ALL current write traffic on whichever shard holds the current date range — the hot-shard problem partitioning-within-one-database doesn't have, because sharding's whole point is spreading load across genuinely separate hardware.
Q: How does a shard key choice affect the difficulty of resharding later (adding more shards)? A: A naive shard-count-based hash (key % N) requires remapping nearly all keys when N changes — this is exactly why consistent hashing (see the Distributed Cache case) is preferred for shard-key hashing in systems expected to grow, since it only remaps a fraction of keys when a shard is added rather than nearly everything.
Q: Is replication lag ever a problem for reads that don't need strict consistency? A: Generally no — a dashboard showing slightly-stale aggregate stats, or a public-facing content read that doesn't need to reflect the last few milliseconds of writes, is exactly the profile where reading from a lagging replica is a perfectly acceptable, even desirable, tradeoff for the read-throughput benefit, which is why not every read needs read-your-own-writes routing, only the specific ones where staleness is user-visible and disruptive.