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

禁用默认事务

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

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

缓存 Prepared Statement

执行任何 SQL 时都创建 prepared statement 并缓存,可以提高后续的调用速度

  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)

带 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)

You can also use GORM API to prepare SQL with DryRun Mode, and execute it with prepared statement later, checkout Session Mode for details

选择字段

默认情况下,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

Iteration / FindInBatches

Query and process records with iteration or in batches

Index Hints

Index is used to speed up data search and SQL query performance. Index Hints gives the optimizer information about how to choose indexes during query processing, which gives the flexibility to choose a more efficient execution plan than the 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`)"