Vertical Partitioning vs Horizontal Sharding
It is critical to distinguish between these two sizing dimensions:
1. Horizontal Sharding
Splits table **rows** across multiple database servers. The schema remains identical across all shards, but each shard stores a unique subset of rows. Ideal for scaling QPS and disk capacities.
2. Vertical Partitioning
Splits table **columns** into separate tables stored on different disks or servers. For example, moving a large text column (`user_bio`) or blob column (`profile_photo_blob`) out of the core `users` table into a secondary `user_profiles` table.
**Benefit**: Reduces the size of the primary table's memory-mapped pages, significantly boosting scan speeds for common narrow queries (e.g. `SELECT username FROM users`).
When Sharding Is Premature
Sharding is an operational tax — cross-shard JOINs disappear, distributed transactions get harder, and rebalancing shards is a multi-week project. Before partitioning horizontally, exhaust vertical scaling and simpler wins: read replicas, connection pooling, query/index tuning, caching hot keys, and archiving cold data. A single well-tuned PostgreSQL instance often carries millions of DAU; interviewers reward candidates who shard only when measured QPS or disk size forces it, not because the problem mentions "scale."
Cross-Shard Operations
Once sharded, queries that span keys on different partitions become expensive:
- Scatter-gather: Fan out to all shards, merge results in the app layer — acceptable for rare admin reports, deadly for user-facing search at high QPS.
- Global secondary indexes: Maintain a separate index shard keyed differently (e.g., email → user_id lookup) with async replication — adds write amplification.
- Co-locate related data: Choose shard key so hot queries hit one partition — user_id shards user posts, orders, and settings together.
Design the shard key around your hottest access path, not around entity nouns in isolation.