GORM 已经优化了许多东西来提高性能,其默认性能对大多数应用来说都够用了。但这里还是有一些关于如何为您的应用改进性能的方法。

禁用默认事务

对于写操作(创建、更新、删除),为了确保数据的完整性,GORM 会将它们封装在一个事务里。但这会降低性能,你可以在初始化时禁用这种方式

  1. db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
  2. SkipDefaultTransaction: true,
  3. })

缓存预编译语句

执行任何 SQL 时都创建并缓存预编译语句,可以提高后续的调用速度

  1. // 全局模式
  2. db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
  3. PrepareStmt: true,
  4. })
  5. // 会话模式
  6. tx := db.Session(&Session{PrepareStmt: true})
  7. tx.First(&user, 1)
  8. tx.Find(&users)
  9. tx.Model(&user).Update("Age", 18)

注意 也可以参考如何为 MySQL 开启 interpolateparams 以减少 roundtrip https://github.com/go-sql-driver/mysql#interpolateparams

带 PreparedStmt 的 SQL 生成器

Prepared Statement 也可以和原生 SQL 一起使用,例如:

  1. db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
  2. PrepareStmt: true,
  3. })
  4. db.Raw("select sum(age) from users where role = ?", "admin").Scan(&age)

您也可以使用 GORM 的 API DryRun 模式 编写 SQL 并执行 prepared statement ,查看 会话模式 获取详情

选择字段

默认情况下,GORM 在查询时会选择所有的字段,您可以使用 Select 来指定您想要的字段

  1. db.Select("Name", "Age").Find(&Users{})

或者定义一个较小的 API 结构体,使用 智能选择字段功能

  1. type User struct {
  2. ID uint
  3. Name string
  4. Age int
  5. Gender string
  6. // 假设后面还有几百个字段...
  7. }
  8. type APIUser struct {
  9. ID uint
  10. Name string
  11. }
  12. // 查询时会自动选择 `id`、`name` 字段
  13. db.Model(&User{}).Limit(10).Find(&APIUser{})
  14. // SELECT `id`, `name` FROM `users` LIMIT 10

迭代、FindInBatches

用迭代或 in batches 查询并处理记录

Index Hints

Index 用于提高数据检索和 SQL 查询性能。 Index Hints 向优化器提供了在查询处理过程中如何选择索引的信息。与 optimizer 相比,它可以更灵活地选择更有效的执行计划

  1. import "gorm.io/hints"
  2. db.Clauses(hints.UseIndex("idx_user_name")).Find(&User{})
  3. // SELECT * FROM `users` USE INDEX (`idx_user_name`)
  4. db.Clauses(hints.ForceIndex("idx_user_name", "idx_user_id").ForJoin()).Find(&User{})
  5. // SELECT * FROM `users` FORCE INDEX FOR JOIN (`idx_user_name`,`idx_user_id`)"
  6. db.Clauses(
  7. hints.ForceIndex("idx_user_name", "idx_user_id").ForOrderBy(),
  8. hints.IgnoreIndex("idx_user_name").ForGroupBy(),
  9. ).Find(&User{})
  10. // SELECT * FROM `users` FORCE INDEX FOR ORDER BY (`idx_user_name`,`idx_user_id`) IGNORE INDEX FOR GROUP BY (`idx_user_name`)"

读写分离

通过读写分离提高数据吞吐量,查看 Database Resolver 获取详情