mysql里面的count(0)、count(1)、count(column)、count(*) 到底用哪一个,看完就明白了

381 阅读3分钟

这是一个非常经典的MySQL面试题。简单直接的答案是:在绝大多数情况下,使用 COUNT(*)

下面我来详细解释这几种写法的区别和最佳实践,让你彻底明白。

结论先行

写法含义推荐度原因
COUNT(*)统计所有行数,不管列值是否为NULL。⭐⭐⭐⭐⭐ 强烈推荐语义最清晰,性能最优(MySQL已经对其做了大量优化)。
COUNT(1)统计所有行数。1 这个常量值不为NULL,所以每一行都计数。⭐⭐⭐⭐ 可以使用性能与 COUNT(*) 完全一样,但语义不如 COUNT(*) 直观。
COUNT(0)同 COUNT(1)0 也是一个常量值。⭐⭐⭐ 不推荐性能一样,但容易让人困惑“为什么要统计0的个数?”,语义不清。
COUNT(column_name)统计指定列中不为NULL的行数。⭐⭐⭐ 按需使用功能不同!如果该列允许为NULL,结果可能小于总行数。

详细分解

1. COUNT(*)

这是 统计表总行数 的标准写法。它的目的非常明确:“给我所有行的数量”。

  • 现代MySQL版本(5.7及以后)对 COUNT(*) 做了大量优化,特别是对于InnoDB引擎。它会选择最小的非NULL二级索引来统计行数,如果没有二级索引,则使用主键索引。它不会去读取每一行的实际数据,因此效率很高。
  • 语义清晰:一看就知道是要计算总记录数。

2. COUNT(1) 和 COUNT(0)

  • COUNT(1) :对于每一行,引擎都会检查括号内的表达式是否为NULL。1 是一个非NULL的常量表达式,因此每一行都会被计数。它的执行过程与 COUNT(*) 完全相同,性能没有任何区别。
  • COUNT(0) :原理同 COUNT(1)0 也是一个非NULL常量。但从代码可读性来看,它不如 COUNT(1) 和 COUNT(*),因为 0 看起来像是一个具体的值,容易产生歧义。

性能真相:在MySQL中,COUNT(*)COUNT(1)COUNT(0)、甚至 COUNT('any_constant_value') 的执行计划(Execution Plan)是完全一样的,性能没有任何差异。你可以用 EXPLAIN 语句来验证这一点。

3. COUNT(column_name)

这是与前三种完全不同的操作!

  • 不是统计总行数,而是统计指定列 column_name 中值不为NULL的行的数量。
  • 如果该列定义了 NOT NULL,那么 COUNT(column_name) 的结果会等于 COUNT(*)
  • 如果该列允许为 NULL,并且表中确实存在 NULL 值,那么 COUNT(column_name) 的结果会小于 COUNT(*)

示例:
假设有一张 users 表,有5条记录,其中 phone 列有1条记录为NULL。

idnamephone
1Alice12345
2Bob67890
3CharlieNULL
4David11111
5Eve22222

sql

SELECT
    COUNT(*),      -- 结果为 5 (总行数)
    COUNT(1),      -- 结果为 5
    COUNT(0),      -- 结果为 5
    COUNT(phone)   -- 结果为 4 (因为有一行的phone是NULL,不被计数)
FROM users;

最终建议与最佳实践

  1. 当你需要【统计表的总行数】时,永远使用 COUNT(*)

    • 理由:这是SQL标准写法,语义最明确,所有人都能一眼看懂。并且MySQL已经对其进行了最优化的处理,性能最好。
  2. 当你需要【统计某列中非NULL值的数量】时,使用 COUNT(column_name)

    • 理由:这是实现该需求的正确语法,例如“统计有多少个用户提供了手机号”。
  3. 避免使用 COUNT(0),因为它语义不清,不能带来任何好处。

  4. 可以接受 COUNT(1),但首选仍然是 COUNT(*)

    • 在一些古老的数据库系统中(或非常旧的MySQL版本),传说 COUNT(*) 效率低,所以很多人养成了写 COUNT(1) 的习惯。但这个说法对于现代MySQL已经完全过时了

总结一句话:数总行数用 COUNT(*),数非空值用 COUNT(列名),其他写法没必要