DryRun模式的真实作用是跳过数据库执行,仅生成SQL字符串和参数,用于验证语句结构与参数正确性;它不测性能,因全程不发包、不等待、不解析结果,无法反映索引、锁、网络等真实瓶颈。

什么是 DryRun 模式的真实作用
DryRun 不是“测试 SQL 性能”的工具,它只做一件事:跳过数据库连接与执行,仅触发 GORM 的 SQL 构建逻辑,返回 stmt.SQL.String() 和 stmt.Vars。你看到的 SQL 是字符串,参数是 Go 切片,全程不发包、不等待、不解析结果——所以它无法反映索引缺失、锁等待、网络延迟等真实瓶颈。
如何正确启用 DryRun 并捕获 SQL
启用方式分两种,必须选对场景:
- 全局启用(调试整个 DB 实例):
gorm.Config{DryRun: true},适合启动时快速验证默认行为 - 单次启用(精准控制某条语句):
db.Session(&gorm.Session{DryRun: true}).First(&u, 1),避免污染其他操作
关键点:必须用 Session 或初始化配置开启,db.Debug() 不会触发 DryRun,它只是把真实执行的 SQL 打印出来。
怎么拿到生成的 SQL 字符串和参数
DryRun 下所有方法(如 First、Create、Updates)仍会返回 *gorm.DB,但内部 Statement 已填充好 SQL 和参数。你需要手动提取:
stmt := db.Session(&gorm.Session{DryRun: true}).Where("name = ?", "foo").Find(&users).Statement
sql := stmt.SQL.String() // "SELECT * FROM `users` WHERE name = ?"
vars := stmt.Vars // []interface{}{"foo"}
注意:Find 等方法不会填充 users 结构体(因为没查库),stmt.SQL.String() 可能含占位符(如 ? 或 $1),具体取决于驱动;MySQL 用 ?,PostgreSQL 用 $1。
容易踩的坑:DryRun 下 Preload/Joins 会失效或报错
Preload 和 Joins 在 DryRun 模式下行为不稳定:
-
Preload通常直接被忽略,不会生成关联查询 SQL -
Joins可能生成 SQL,但关联字段别名、ON 条件可能丢失或错位 - 如果你依赖
Preload("Orders")验证多表 JOIN 逻辑,DryRun 结果不可信,必须切回真实执行 +EXPLAIN
真正需要确认关联 SQL 时,建议用 db.Debug().Preload(...).Find(...) 配合日志观察,而不是依赖 DryRun。


















