|$ curl https://forge-ai.dev/api/markdown?path=docs/system-design/databases
$cat docs/databases-at-scale.md
updated Recently·35 min read·published

Databases at Scale

System DesignAdvanced🎯Free Tools
Introduction

The database is the beating heart of most applications, and it is usually the first component to buckle under load. Scaling a database is harder than scaling stateless application servers because data has gravity: it is heavy to move, expensive to duplicate, and sensitive to consistency semantics.

This guide covers the techniques used to scale relational and non-relational databases: replication for availability and read throughput, sharding for write throughput, indexing for query speed, partitioning for manageability, and the CAP theorem tradeoffs that shape every distributed datastore.

By the end, you should be able to reason about when to add replicas, when to shard, when to denormalize, and when to trade strong consistency for availability.

Replication

Replication copies data from a primary node to one or more replica nodes. It improves availability — if the primary fails, a replica can be promoted — and read throughput — read queries can be distributed across replicas. The cost is complexity: replicas lag behind the primary, and failover must be handled carefully to avoid split-brain.

primary-replica.txt
TEXT
1Primary-Replica Replication:
2
3 ┌─────────────┐
4 │ Writes │
5 └──────┬──────┘
6
7 ┌──────▼──────┐
8 │ Primary │
9 │ (read+write)│
10 └──────┬──────┘
11 │ replication stream
12 ┌───────┼───────┐
13 │ │ │
14┌──────▼───┐ ┌─▼─────┐ ┌─▼─────┐
15│ Replica 1│ │Repl. 2│ │Repl. 3│
16│ (reads) │ │(reads)│ │(reads)│
17└──────────┘ └───────┘ └───────┘

Synchronous vs Asynchronous Replication

In synchronous replication, the primary waits for at least one replica to acknowledge a write before committing it to the client. This guarantees durability but increases write latency. In asynchronous replication, the primary acknowledges immediately and replicates in the background. It is faster but risks data loss if the primary fails before replication completes.

ModeDurabilityLatencyUse Case
AsyncPossible data loss on failoverLowMost web applications, analytics
SyncNo loss if acknowledgedHigherFinancial systems, inventory
Semi-syncAt least one replica has itModerateBalanced workloads

warning

Promoting a replica to primary during failover can lose un-replicated writes. Plan for this with automatic failover tools, but always understand the recovery point objective (RPO) of your replication topology.
Sharding

Sharding partitions data across multiple independent database instances. Each shard contains a subset of the data and handles its own reads and writes. When a single node cannot handle the write volume or dataset size, sharding allows the cluster to scale horizontally.

sharding.txt
TEXT
1Application-level sharding:
2
3shard_id = hash(user_id) % shard_count
4db = shard_router[shard_id]
5
6User A ──▶ hash(A) % 4 = 1 ──▶ Shard 1
7User B ──▶ hash(B) % 4 = 3 ──▶ Shard 3
8User C ──▶ hash(C) % 4 = 0 ──▶ Shard 0
9
10Queries by user_id are routed to a single shard.
11Cross-shard queries must be split and merged.

Shard Key Selection

The shard key determines how data is distributed. A poor choice creates hot shards, where one node receives disproportionate traffic. A good shard key has high cardinality, even distribution, and aligns with query patterns.

StrategyDistributionQuery PatternRisk
Hash of IDEvenPoint lookupsCross-shard range queries
Range of IDUnevenRange scansHot ranges, write skew
Tenant IDDepends on tenant sizesTenant isolationNoisy neighbor problem
CompositeTunableDomain-specificComplex routing logic

best practice

Avoid resharding if possible. Use consistent hashing or a logical shard map that maps many logical shards to fewer physical nodes. When you add nodes, only a fraction of logical shards move.
Indexing

Indexes are data structures that speed up reads at the cost of slower writes and additional storage. Without an index, a database scans every row to answer a query. With the right index, the same query touches only a handful of pages.

B-Trees

B-trees are the default index type in most relational databases. They keep data sorted and balanced, allowing logarithmic-time lookups, range scans, and ordered iteration. B-trees work well for equality and range queries on stable, ordered keys.

Hash Indexes

Hash indexes map keys directly to disk locations using a hash function. They provide O(1) equality lookups but cannot support range queries or ordering. They are common in key-value stores like Redis and DynamoDB partition keys.

Index TypeBest ForLimitations
B-TreeRange queries, sorting, equalityWrite amplification on inserts
HashExact key lookupsNo range or prefix queries
BitmapLow-cardinality columnsNot suitable for high-cardinality data
GIN / GiSTFull-text search, JSON, arraysLarger storage, slower writes
InvertedSearch engines, documentsMerge and update costs

info

Index every column used in WHERE, JOIN, and ORDER BY clauses — but not blindly. Each index slows writes and consumes disk. Use EXPLAIN plans to verify the query planner is using the index you expect.
Partitioning

Partitioning splits a single logical table into smaller physical chunks within the same database. Unlike sharding, partitioning is usually transparent to the application. It improves query performance and maintenance — old partitions can be archived or dropped cheaply.

partitioning.txt
TEXT
1Time-based partitioning for event logs:
2
3CREATE TABLE events (
4 id BIGINT,
5 created_at TIMESTAMP,
6 payload JSONB
7) PARTITION BY RANGE (created_at);
8
9CREATE TABLE events_2026_01 PARTITION OF events
10 FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
11
12CREATE TABLE events_2026_02 PARTITION OF events
13 FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');
14
15-- Query planner prunes partitions outside the range.
16SELECT * FROM events WHERE created_at > '2026-01-15';
📝

note

Partitioning works best when queries have a natural filter on the partition key. Without that filter, the database scans every partition, which is slower than scanning a single unpartitioned table.
CAP Theorem in Practice

The CAP theorem states that a distributed data store cannot simultaneously provide Consistency, Availability, and Partition tolerance. In practice, network partitions are unavoidable, so the real choice is between consistency and availability during a partition.

PropertyDescriptionExample System
CPConsistent and partition-tolerant; may refuse writes during partitionetcd, ZooKeeper, HBase
APAvailable and partition-tolerant; reads may be staleCassandra, DynamoDB, Riak
CAConsistent and available, but not partition-tolerantSingle-node databases

best practice

Do not choose CP or AP globally. Most real systems are partition-tolerant and allow per-operation consistency. DynamoDB lets you specify strongly consistent reads per request; Cassandra lets you tune consistency levels per query.
Read Replicas in Detail

Read replicas are the lowest-friction way to scale read-heavy workloads. They are asynchronous copies of the primary database that accept read traffic. The pattern is simple: writes go to the primary; reads go to replicas, with critical reads optionally forced to the primary.

read-routing.txt
TEXT
1Read routing logic:
2
3function executeQuery(query, requireStrongConsistency) {
4 if (query.isWrite()) {
5 return primary.execute(query);
6 }
7 if (requireStrongConsistency) {
8 return primary.execute(query); // fresh read
9 }
10 return loadBalancer.pick(replicas).execute(query); // stale read
11}

warning

Replication lag can confuse users. If a user posts a comment and immediately refreshes, the replica might not have it yet. Force critical reads to the primary or use session causality tracking to ensure users see their own writes.
Choosing the Right Database

There is no best database. The right choice depends on data shape, access patterns, consistency needs, and operational expertise. Modern architectures often use multiple databases — a pattern called polyglot persistence.

WorkloadTypical ChoiceWhy
Relational transactionsPostgreSQL, MySQLACID, joins, complex queries
High-write key-valueDynamoDB, ScyllaDBMassive scale, predictable latency
Caching / sessionsRedis, KeyDBSub-millisecond latency, TTL
Full-text searchElasticsearch, OpenSearchInverted indexes, relevance scoring
Time-seriesInfluxDB, TimescaleDBTime-based compression, retention
Graph dataNeo4j, Amazon NeptuneRelationship traversal
🔥

pro tip

Start with the database your team knows best. Prematurely adopting a distributed database for a workload that fits a single PostgreSQL instance adds operational risk without meaningful benefit.
$Blueprint — Engineering Documentation·Section ID: SD-DB-01·Revision: 1.0