订阅更新

SQL COUNT(*)、COUNT(1) 和 COUNT(列) 有什么区别?

面试问 057 约 3 分钟读完 2 次阅读

本文目录
  1. 面试怎么回答
  2. 三种写法分别统计什么?
  3. COUNT() 和 COUNT(1) 谁更快?
  4. COUNT(列) 什么时候有用?
  5. 两个常见坑

面试怎么回答

COUNT() 统计结果集行数;COUNT(1) 统计常量表达式非 NULL 的行数,因此通常与 COUNT() 结果一致;COUNT(列) 会忽略该列为 NULL 的行。现代优化器下 COUNT() 和 COUNT(1) 往往执行计划相同或等价,不能脱离引擎断言谁一定更快。统计总行数我优先用 COUNT(),统计有效字段或 LEFT JOIN 右表匹配数时才用 COUNT(列)。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

同一张表执行三条 SQL:

SELECT COUNT(*) FROM t;
SELECT COUNT(1) FROM t;
SELECT COUNT(user_id) FROM t;

前两个结果相同,第三个却更小。原因通常不是性能,而是:COUNT(列) 不统计 NULL。

先记住结论:COUNT(*) 统计行数,COUNT(常量) 统计常量表达式非 NULL 的行数,COUNT(列) 只统计该列非 NULL 的行数。


三种写法分别统计什么?

假设数据是:

id | user_id
1  | A
2  | NULL
3  | B

结果为:

COUNT(*)       = 3
COUNT(1)       = 3
COUNT(user_id) = 2

COUNT(*) 不关心某一列是否为空,只统计结果集有多少行。

COUNT(1) 中的 1 是每行都非 NULL 的常量,因此通常也统计所有行。写成 COUNT(0)、COUNT('x'),语义上也类似。

COUNT(user_id) 会忽略 user_id IS NULL 的行。

COUNT 三种写法结果对比


COUNT(*) 和 COUNT(1) 谁更快?

不要脱离数据库引擎、版本和执行计划给出绝对答案。

现代优化器通常能识别两者都是统计行数,并生成相同或等价的执行计划。实际耗时更多受这些因素影响:

  • 是否需要扫描整表或可以利用元数据、索引
  • 存储格式和列裁剪能力
  • 过滤条件选择性
  • 并行度、分区裁剪与缓存
  • 分布式引擎是否需要全局聚合

如果业务意图是统计行数,优先写 COUNT(*),语义最清楚。不要为了传闻中的微小性能差异牺牲可读性。


COUNT(列) 什么时候有用?

它适合统计某字段的有效值数量,例如:

SELECT
  COUNT(*) AS total_rows,
  COUNT(phone) AS phone_filled_rows,
  COUNT(*) - COUNT(phone) AS phone_null_rows
FROM user_profile;

还要注意 COUNT(DISTINCT col) 同样会忽略 NULL,并对非 NULL 值去重。多个字段的 DISTINCT 语义与支持方式,则要以具体引擎为准。


两个常见坑

LEFT JOIN 后用错 COUNT

SELECT a.id, COUNT(*)
FROM a LEFT JOIN b ON a.id = b.a_id
GROUP BY a.id;

即使右表没有匹配,LEFT JOIN 仍会保留一行,所以 COUNT(*) 可能是 1。若要统计匹配到的右表记录,应统计右表非空键,例如 COUNT(b.id)。

把 NULL 当成零或空字符串

NULL、0 和 '' 是不同状态。COUNT(col) 只忽略 NULL,不会忽略 0 或空字符串。


刷题进度保存在当前浏览器