Problem
A multi-tenant database grows beyond a single node, and a few large tenants degrade performance for everyone. Cross-tenant queries are rare, yet all data shares one failure and scaling domain.
Also known as: tenant-partitioning, shard-per-tenant
Distribute data and load across shards using the tenant identifier as the partition key.
A multi-tenant database grows beyond a single node, and a few large tenants degrade performance for everyone. Cross-tenant queries are rare, yet all data shares one failure and scaling domain.
Tenant sharding uses the tenant as the unit of partitioning. Because most SaaS queries belong to a single customer, almost all reads and writes hit exactly one shard, avoiding scatter-gather.
request(tenant=acme) -> router -> directory: acme -> shard-7
-> connect shard-7 -> query WHERE tenant_id = acme
A directory table (cached in the router) stores tenant id, shard id and state. Hash-based routing is simpler but cannot move one tenant without remapping others; a directory allows targeted moves, and it can be combined with consistent hashing for initial placement.
Tenant moves follow a standard sequence: mark the tenant as migrating, bulk copy, replicate ongoing changes, pause writes briefly, verify checksums, update the directory, resume, and drop the old copy. Keep tenant id as the leading column of primary keys and indexes so data stays clustered and queries are efficient.
Provision shards by capacity, not count. Track per-tenant storage, queries per second and connection use so you can pre-emptively move a growing tenant.
More database clusters; dedicated shards for big tenants
High: routing, migrations, rebalancing
High: directory and move tooling
A whale tenant saturates its shard
Directory lookup outage blocks all routing
Failed tenant move leaves data split between shards