GORM 分表策略实现
GORM 分表通过 Table() 方法动态切换目标表名,结合业务规则实现数据水平拆分。
分表核心机制
Table 方法动态切换
Go
// 动态指定表名
db.Table("orders_202605").Create(&order)
db.Table("orders_202605").Where("user_id = ?", uid).Find(&orders)
Scopes 复用分表逻辑
Go
func ByMonth(table string) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
return db.Table(table)
}
}
// 使用
db.Scopes(ByMonth("orders_202605")).Create(&order)
按时间分表
月份分表实现
Go
type Order struct {
ID uint `gorm:"primaryKey"`
UserID uint `gorm:"index"`
Amount decimal.Decimal
CreatedAt time.Time
}
func getOrderTable(t time.Time) string {
return fmt.Sprintf("orders_%d%02d", t.Year(), t.Month())
}
func CreateOrder(db *gorm.DB, order *Order) error {
table := getOrderTable(order.CreatedAt)
return db.Table(table).Create(order).Error
}
func QueryOrdersByMonth(db *gorm.DB, year, month int) ([]Order, error) {
table := fmt.Sprintf("orders_%d%02d", year, month)
var orders []Order
err := db.Table(table).Where("created_at >= ? AND created_at < ?",
time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC),
time.Date(year, time.Month(month+1), 1, 0, 0, 0, 0, time.UTC),
).Find(&orders).Error
return orders, err
}
按哈希分表
用户 ID 哈希分表
Go
func getUserTable(userID uint) string {
// 按 16 张表哈希路由
shard := userID % 16
return fmt.Sprintf("users_%02d", shard)
}
func CreateUser(db *gorm.DB, user *User) error {
table := getUserTable(user.ID)
return db.Table(table).Create(user).Error
}
func GetUserByID(db *gorm.DB, userID uint) (*User, error) {
table := getUserTable(userID)
var user User
err := db.Table(table).First(&user, userID).Error
return &user, err
}
哈希分表通用函数
Go
func HashSharding(key string, shards int) string {
h := fnv.New32a()
h.Write([]byte(key))
return fmt.Sprintf("table_%02d", h.Sum32()%uint32(shards))
}
自动建表处理
迁移检查
Go
func AutoMigrateShard(db *gorm.DB, table string) error {
// 检查表是否存在
if !db.Migrator().HasTable(table) {
// 克隆表结构并创建
return db.Exec("CREATE TABLE " + table + " LIKE orders_template").Error
}
return nil
}
注意: 分表场景下
AutoMigrate需针对每个分片表单独执行,建议预先创建未来一段时间的分表。
跨分表查询
合并查询结果
Go
func QueryAcrossShards(db *gorm.DB, months []string) ([]Order, error) {
var allOrders []Order
for _, month := range months {
table := "orders_" + month
var orders []Order
if err := db.Table(table).Find(&orders).Error; err != nil {
return nil, err
}
allOrders = append(allOrders, orders...)
}
return allOrders, nil
}
注意: 跨分表查询无法使用单表索引优化,数据量大时应限制查询范围或引入 ES 等检索引擎。
要点总结
- 使用
Table()方法动态切换目标表名 - 按时间分表适合日志、订单等时序数据
- 按哈希分表适合用户、账户等均匀分布数据
- Scopes 可封装分表逻辑提高复用性
- 跨分表查询需合并结果,性能较差,应限制查询范围
存放路径:D:\git2\jwdev\articles\GORM\专家\分库分表与多租户\分表策略实现.md
📝 发现内容有误?点击此处直接编辑