sum和avg跳过null,若整列为空则返回null而非0,易被误读为“无数据”;count(*)统计所有行,count(col)仅统计非null值;having只能引用分组或聚合字段;avg慢主因是全表扫描或隐式转换。

为什么 SUM 和 AVG 对 NULL 的处理会让结果“消失”
因为它们自动跳过 NULL,但如果你没意识到字段本身可能全为 NULL,查询会返回 NULL 而不是 0 或空结果——这在报表里常被误读成“没数据”,其实是“有数据但全是空值”。
-
SUM(col)和AVG(col)忽略NULL,但若整列都是NULL,结果就是NULL,不是0 - 想强制转 0,得用
COALESCE(SUM(col), 0),别只写IFNULL(MySQL)或ISNULL(SQL Server),不同方言函数名不同 - 聚合前没加
WHERE col IS NOT NULL,可能把脏数据也卷进来,比如日志表里amount字段本该非空,但因写入失败留了NULL
COUNT(*) 和 COUNT(col) 的行为差异直接影响分页总数
前者统计行数,后者只统计 col 非 NULL 的行数。在用户注册率、订单支付率这类指标里,错用会导致百分比偏差超 20%。
-
COUNT(*)最快,引擎通常走元数据或主键索引,不读具体字段 -
COUNT(col)必须检查每行该列是否为NULL,如果col没索引,性能明显下降 - 统计“有效提交数”时,别写
COUNT(submit_time)——万一字段允许NULL且部分未赋值,就漏掉了“已提交但时间未写入”的脏记录
GROUP BY 后加 HAVING 过滤比 WHERE 更容易出错
很多人以为 HAVING 就是“对聚合结果的 WHERE”,但它的执行时机晚于 GROUP BY,字段可见性完全不同:你只能用 SELECT 中出现的聚合字段或分组字段,否则报错 column not in GROUP BY。
- 错误写法:
HAVING created_at > '2024-01-01'——created_at没出现在GROUP BY里,也不在聚合中,直接报错 - 正确写法:
HAVING MAX(created_at) > '2024-01-01'或先在WHERE过滤时间范围,再聚合 - MySQL 5.7+ 默认开启
sql_mode=only_full_group_by,不满足规则直接拒查,别急着关它,先理清逻辑依赖
大表上 AVG 计算慢?问题往往不在函数本身
AVG 本质是 SUM(col)/COUNT(col),开销和 SUM + COUNT 差不多。真正拖慢的是没走索引、扫描全表,或者字段类型隐式转换导致索引失效。
- 如果
col是VARCHAR但存数字,AVG(col)会触发隐式转DOUBLE,索引无法使用 - 复合索引
(status, amount)下,WHERE status = 'paid' GROUP BY status能用上索引;但加了AVG(amount)后,如果amount不在索引覆盖范围内,仍要回表 - 单次查千万级订单平均金额,优先考虑物化中间结果(如每日汇总表),而不是每次实时算
聚合函数看着简单,但每个参数背后都连着数据质量、索引策略和 SQL 执行计划。最常被忽略的是:你以为在算业务指标,其实数据库正在默默过滤掉你根本没注意到的 NULL 分支。










