概述
在 SQL 查询中,COUNT 函数是最常用的聚合函数之一,用于统计行数。然而,很多开发者会对 COUNT(*) 和 COUNT(1) 的区别感到困惑,甚至在一些老教程中还能看到'COUNT(1) 比 COUNT(*) 更快'的说法。本文将深入探讨这两者的本质、性能差异以及正确的使用场景。
一、基本概念
COUNT(*)
COUNT(*) 统计表中的所有行数,包括值为 NULL 的行。这里的星号并不代表'所有列',而是一个特殊的语法,表示'整个行'。
COUNT(1)
COUNT(1) 统计表达式 1 不为 NULL 的行数。由于常量 1 永远不为 NULL,所以它同样会统计表中的所有行,结果与 COUNT(*) 完全一致。
示例:
假设有一张用户表 users,包含 3 行数据,其中一行的 email 字段为 NULL:
SELECT COUNT(*) FROM users; -- 返回 3
SELECT COUNT(1) FROM users; -- 返回 3
SELECT COUNT(email) FROM users; -- 返回 2(忽略 NULL)
二、性能对比:现代 MySQL 中无差异
在 MySQL 5.7 及更高版本中,优化器会将 COUNT(1) 自动重写为 COUNT(*),因此两者的执行计划完全相同。我们可以通过 EXPLAIN 来验证:
EXPLAIN SELECT COUNT(*) FROM users;
EXPLAIN SELECT COUNT(1) FROM users;
两者的输出结果(如 id、select_type、Extra 等字段)没有任何区别。这意味着它们在性能上是完全等价的,不存在谁比谁快的问题。
为什么早期会有'COUNT(1) 更快'的说法?
在非常古老的 MySQL 版本(如 3.23)中, 的实现方式可能涉及读取所有列,而 只需读取常量,因此确有性能差异。但,现代优化器对 做了专门优化,它会选择最优的索引(通常是二级索引)来统计行数,而不是全表扫描。

