group by后必须将所有非聚合字段列入group by子句,否则严格模式下报错;sum()自动忽略null但返回null而非0,需coalesce处理;where过滤行、having过滤分组;索引优化对性能至关重要。

GROUP BY 后直接用 SUM() 就行,但必须注意字段是否在 GROUP BY 中
SELECT 里只要用了 SUM(),所有非聚合字段都得出现在 GROUP BY 子句中,否则多数数据库(如 MySQL 5.7+、PostgreSQL、SQL Server)会报错:ERROR 1055: Expression #1 of SELECT list is not in GROUP BY clause。MySQL 8.0 默认开启严格模式,这个限制比以前更硬。
常见写法是:
SELECT category, SUM(amount) AS total FROM orders GROUP BY category;
如果误写成:
SELECT category, user_id, SUM(amount) FROM orders GROUP BY category;
就会失败——user_id 既没被聚合,也没出现在 GROUP BY,数据库不知道该取哪一行的 user_id。
SUM() 遇到 NULL 会自动跳过,但要注意空表或全 NULL 的结果是 NULL
SUM() 对 NULL 值完全忽略,这通常符合预期;但如果分组内所有值都是 NULL,或者整个分组为空(比如 LEFT JOIN 后没匹配到数据),SUM() 返回 NULL,不是 0。
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
- 想统一转成
0,得用COALESCE(SUM(amount), 0) - 如果字段本身允许
NULL,且业务上“没金额”和“金额为 0”有区别,就别盲目COALESCE,否则掩盖语义差异 - 在 WHERE 条件里提前过滤掉
amount IS NULL不影响SUM()行为,因为本来就不参与计算
WHERE 和 HAVING 的分工:过滤行用 WHERE,过滤分组用 HAVING
WHERE 在分组前生效,HAVING 在 SUM() 计算完之后才起作用。比如要查“总金额超过 1000 的品类”,必须写:
SELECT category, SUM(amount) AS total FROM orders GROUP BY category HAVING SUM(amount) > 1000;
不能写成 WHERE SUM(amount) > 1000——那会报错,因为 SUM() 是聚合结果,WHERE 看不到它。
-
WHERE status = 'paid'可以放在前面,先筛出行,再分组求和 - 如果同时需要行级过滤和分组后筛选,两个子句都要用,顺序不能颠倒
-
HAVING里可以用别名吗?MySQL 支持,PostgreSQL 不支持,稳妥起见还是写完整表达式HAVING SUM(amount) > 1000
性能提示:SUM() 本身不慢,但 GROUP BY 的代价常被低估
SUM() 函数开销极小,真正拖慢查询的通常是 GROUP BY 引发的排序或临时表。特别是当分组字段没有索引,或分组键基数很高(比如按用户 ID 分组百万用户),数据库可能被迫做全表扫描 + 内存排序。
- 确保
GROUP BY字段上有索引,尤其是复合索引里把分组列放最左 - 避免在
GROUP BY里用函数,比如GROUP BY YEAR(order_date)会让索引失效 - 如果只是要总数,别画蛇添足
GROUP BY 1=1——直接SUM()就够了
分组求和看着简单,实际卡点往往不在 SUM() 本身,而在数据分布、索引设计和执行计划是否走对路。










