Database sharding is the process of splitting a large table into multiple smaller databases (shards), where each shard holds a subset of your total data. This makes your application more scalable, performant, and fault-tolerant.
Our Rails app was receiving lakhs of orders in real time. Our orders
table became a bottleneck:
We had to scale horizontally—without rewriting the whole app.
orders
Table by user_id
We split the orders into 8 databases:
order_shard_0
to order_shard_7
user_id % 8
to route trafficdatabase.yml
Setupproduction:
primary:
database: app_primary
adapter: postgresql
order_shard_0:
database: app_orders_0
adapter: postgresql
# ...up to order_shard_7
class OrderBase < ApplicationRecord
self.abstract_class = true
end
class Order < OrderBase
belongs_to :user
end
module ShardRouter
SHARDS = %i[order_shard_0 order_shard_1 ... order_shard_7]
def self.for_user(user_id)
SHARDS[user_id % SHARDS.size]
end
end
class OrderService
def initialize(user_id)
@user_id = user_id
@shard = ShardRouter.for_user(user_id)
end
def create_order(params)
ActiveRecord::Base.connected_to(database: @shard) do
Order.create!(params.merge(user_id: @user_id))
end
end
def fetch_latest_orders(limit = 10)
ActiveRecord::Base.connected_to(database: @shard) do
Order.where(user_id: @user_id).order(created_at: :desc).limit(limit)
end
end
end
service = OrderService.new(current_user.id)
service.create_order(price: 100, quantity: 2, symbol: "RELIANCE")
orders = service.fetch_latest_orders
Yes, you can do order.user
. But Rails does this in two queries:
SELECT * FROM orders ... -- shard
SELECT * FROM users ... -- primary DB
order.user
✅order.build_user
✅User.has_many :orders
❌Order.includes(:user)
❌user_id
(or other sharding key) consistentlyMetric | Before | After |
---|---|---|
Order fetch (10 rows) | ~500ms | ~80ms |
Write throughput | Saturated | Smooth |
Lock contention | High | Low |
Sharding helped us break through scaling walls. It takes effort—but if you're hitting database limits, this might be your solution too.
orders
by user_id % 8
connected_to
in service layerQuestions or thoughts? Email me