Sharding
Route model queries and writes to configured shard connections.
Sharding is a core routing feature. It maps a model query to one of several configured connections through a shard strategy.
Configure shards
db, err := oro.Open(oro.Config{
Connections: map[string]oro.ConnectionConfig{
"orders_0": {Driver: mysql.Open(dsn0)},
"orders_1": {Driver: mysql.Open(dsn1)},
},
Shards: map[string]oro.ShardConfig{
"orders": {
Connections: []string{"orders_0", "orders_1"},
Strategy: oro.ModShard("TenantID"),
},
},
})
ModShard(field) hashes an integer-like field by modulo over the configured connection list.
Model sharding
A model opts into a shard group in Define:
type Order struct {
oro.Model
TenantID uint64
Code string
Total uint
}
func (Order) Define(s *oro.SchemaBuilder) {
s.Table("orders")
s.Shard("orders", "TenantID")
s.Field("TenantID").UnsignedBigInt().Index()
s.Field("Code").String().Unique()
s.Field("Total").Uint()
}
The field names passed to Shard are Go field names.
Query one shard
Pass shard values explicitly:
orders, err := db.Use[Order]().
Shard(oro.Map{"TenantID": uint64(10)}).
Where("Code", "A001").
Get(ctx)
Writes also require shard values:
created, err := db.Use[Order]().
Shard(oro.Map{"TenantID": uint64(10)}).
Create(ctx, &Order{TenantID: 10, Code: "A001", Total: 120})
If a sharded model is queried or written without shard values, Oro returns oro.ErrShardRequired.
Query all shards
Use AllShards() for read-oriented fan-out queries:
orders, err := db.Use[Order]().
AllShards().
Where("Status", "paid").
OrderBy("Code").
Get(ctx)
AllShards fans the query out to every configured shard connection. For Get, First, and pagination it performs a global merge: rows from all shards are combined, sorted by the query’s ORDER BY, and then LIMIT / OFFSET are applied globally across the merged result. Keep it for reads or controlled maintenance flows.
:::note[Global ordering and paging]
All-shard reads now merge and order globally instead of concatenating each shard’s rows. Earlier versions applied LIMIT / OFFSET per shard, so ordering and pagination across shards were incorrect. Because the merge happens in memory, an explicit ORDER BY is required for any ordered all-shard read. First() over AllShards() returns the global-first row and reports oro.ErrOrderRequired when no ORDER BY is set.
:::
Cross-shard aggregates
Count over AllShards() is supported and sums the per-shard counts:
total, err := db.Use[Order]().
AllShards().
Where("Status", "paid").
Count(ctx)
Sum, Avg, Min, and Max cannot be computed correctly by merging per-shard values, so over AllShards() they now return oro.ErrUnsupported instead of silently returning a single shard’s result. Compute these at the application layer (or per shard) when you need them across shards.
Transactions
A single transaction cannot span multiple shards. If a write path needs more than one shard, coordinate it at the application layer.
Tenant extension integration
The extensions/tenant package can provide shard values automatically. See Tenant Extension when shard routing is tenant-based.