GORM 查询计划分析与优化
查询计划是数据库优化核心,本文介绍使用 EXPLAIN 分析 GORM 生成的 SQL 并优化索引使用。
什么是查询计划
查询计划是数据库引擎执行 SQL 时采用的策略,包括扫描方式、索引选择、连接顺序等。
使用 EXPLAIN 分析查询
在 GORM 中获取 SQL 后,使用 EXPLAIN 分析执行计划。
Go
// 1. 获取 GORM 生成的 SQL
stmt := db.ToSQL(func(tx *gorm.DB) *gorm.DB {
return tx.Where("email = ?", "test@example.com").Find(&User{})
})
fmt.Println(stmt)
// SELECT * FROM users WHERE email = 'test@example.com'
SQL
-- 2. 使用 EXPLAIN 分析
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
关键指标:
| 字段 | 说明 | 优化目标 |
|---|---|---|
| type | 连接类型 | ALL < index < range < ref < const |
| key | 使用的索引 | 应为预期索引 |
| rows | 扫描行数 | 越小越好 |
| Extra | 额外信息 | 避免 Using filesort |
索引优化
创建索引
Go
// GORM 索引定义
type User struct {
ID uint
Email string `gorm:"index"` // 单列索引
Name string `gorm:"index:idx_name"` // 命名索引
}
复合索引
多条件查询使用复合索引,注意最左匹配原则。
Go
type User struct {
ID uint
Status string `gorm:"index:idx_composite"`
Type string `gorm:"index:idx_composite"`
}
SQL
-- 可命中索引
EXPLAIN SELECT * FROM users WHERE status = 'active'; -- 命中
EXPLAIN SELECT * FROM users WHERE status = 'active' AND type = 1; -- 命中
EXPLAIN SELECT * FROM users WHERE type = 1; -- 不命中(非最左列)
常见优化场景
1. 全表扫描优化
避免 SELECT *,仅查询需要的列。
Go
// 错误:全表扫描所有列
db.Find(&users)
// 优化:仅查询必要列
db.Select("id", "name", "email").Find(&users)
2. LIKE 查询优化
前缀匹配可走索引,前后通配符导致全表扫描。
SQL
-- 可走索引
EXPLAIN SELECT * FROM users WHERE name LIKE '张%';
-- 全表扫描
EXPLAIN SELECT * FROM users WHERE name LIKE '%张%';
3. 分页查询优化
大偏移量分页性能差,使用游标分页。
Go
// 错误:大偏移量
db.Offset(100000).Limit(20).Find(&users)
// 优化:游标分页
db.Where("id > ?", lastID).Order("id").Limit(20).Find(&users)
- **EXPLAIN 是离线分析:**不会实际执行 SQL,可放心在生产排查。
- **索引非万能:**过度索引影响写入性能,定期清理无用索引。
- **执行计划会变化:**数据分布变化可能导致优化器选择不同计划,定期复查。
要点总结
| 优化手段 | 核心要点 |
|---|---|
| EXPLAIN 分析 | 关注 type、key、rows 指标 |
| 索引优化 | 单列/复合索引,注意最左匹配 |
| 列裁剪 | 避免 SELECT *,仅查必要字段 |
| 分页优化 | 大偏移量改用游标分页 |
- 使用 EXPLAIN 分析查询计划,定位性能瓶颈。
- 合理使用索引,遵循最左匹配原则。
- 避免 SELECT * 和大偏移量分页。
- 执行计划会随数据变化,需定期复查。
存放路径: D:\git2\jwdev\articles\GORM\专家\性能优化与调优\查询计划分析与优化.md
📝 发现内容有误?点击此处直接编辑