count统计必须用count()而非find()+len(),因其生成count(*)sql、节省资源;聚合函数需model().select().scan()配合coalesce防空结果;groupby统计须用scan接收结构体;软删除需unscoped(),关联聚合需显式joins()。

Count统计必须用 Count(),不能用 Find() + len()
直接查出所有记录再用 len() 计算数量,不仅浪费内存和带宽,还可能触发全表扫描导致超时。GORM 的 Count() 会生成 SQL 的 COUNT(*) 或 COUNT(字段),只返回一个整数。
常见错误是写成:
var users []User
db.Where("status = ?", 1).Find(&users)
count := len(users) // 错!数据量大时崩得悄无声息
正确做法是:
var count int64
db.Model(&User{}).Where("status = ?", 1).Count(&count)
注意:Count() 必须传入 *int64 类型变量;若用 int(如 int 或 uint),在 32 位系统或大数据量时可能溢出。
聚合函数要用 Model().Select().Scan() 或 Raw()
GORM 不提供 SUM()、AVG()、MAX() 等的独立方法,得靠 Select() 搭配 Scan() 手动映射。例如统计总金额:
var total float64
db.Model(&Order{}).Where("user_id = ?", userID).Select("COALESCE(SUM(amount), 0)").Scan(&total)
关键点:
-
Model(&T{})是必须的,否则Select()不知道作用于哪张表 -
COALESCE(..., 0)很重要:空结果集时避免Scan()返回sql.ErrNoRows - 如果聚合结果含多个字段(如
AVG(price), COUNT(*)),需定义结构体接收,字段名要与Select()别名一致 - 不推荐用
Raw()写原生 SQL,除非有复杂子查询或数据库特有函数——它绕过 GORM 的链式构建逻辑,难维护也难测试
带 GroupBy 的 Count 和聚合必须用 Group() + Scan()
想按状态分组统计用户数?别试图用 Count() 配合 Group() ——它不支持返回多行结果。必须用 Scan() 接收切片:
type StatusCount struct {
Status int `gorm:"column:status"`
Count int64 `gorm:"column:count"`
}
var results []StatusCount
db.Model(&User{}).Select("status, COUNT(*) as count").Group("status").Scan(&results)
注意:
-
Select()中的别名(如as count)必须与结构体字段的gorm:"column:..."标签或字段名完全匹配 - 没有
Where()时,Group()可能扫全表,记得加索引(如INDEX idx_status ON users(status)) - 若结构体字段类型不匹配(比如数据库
COUNT(*)是int8,但结构体用int),Scan 会静默失败或返回零值
Count 和聚合在事务/关联场景下容易漏掉 Unscoped() 或 Joins()
软删除模型调用 Count() 默认忽略 deleted_at IS NULL 条件,结果比预期少;一对多聚合时没显式 Joins(),可能因 LEFT JOIN 缺失导致计数偏差。
例如统计每个用户的订单数(含 0 订单用户):
db.Model(&User{}).Select("users.id, COALESCE(COUNT(orders.id), 0) as order_count").
Joins("LEFT JOIN orders ON orders.user_id = users.id").
Group("users.id").Scan(&results)
而如果只想统计“未软删除”的用户总数,得加:
db.Unscoped().Model(&User{}).Where("deleted_at IS NOT NULL").Count(&count)
这里容易忽略的是:Unscoped() 要放在 Model() 之后、任何条件之前;且它影响整个链式调用,别误加在其它查询里污染逻辑。
聚合本身不缓存,也不走预加载机制,该写 JOIN 就写 JOIN,别指望 Preload() 能帮上忙。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











