Mysql:count(1)和count(*)和count(主键字段)有什么区别?
2026/8/6 17:30:09 网站建设 项目流程

一、三种写法分别是什么意思

1.COUNT(*)

SELECT COUNT(*) FROM users;

表示:

统计结果集中的行数,不管这一行的字段是否为NULL

这是最标准、最清晰的“统计行数”写法。

2.COUNT(1)

SELECT COUNT(1) FROM users;

1是一个永远不为NULL的常量。

对于结果集中的每一行,MySQL 都可以得到一个非NULL1,所以最终统计的仍然是行数:

每行 -> 计算出 1 -> 计数加一

因此,对 InnoDB 来说:

COUNT(*) COUNT(1)

MySQL 官方明确说明,这两种写法处理方式相同,没有性能差异。

3.COUNT(主键字段)

SELECT COUNT(id) FROM users;

它统计的是:

id字段不为NULL的行数。

如果id是真正的主键,那么主键必然是NOT NULL,因此:

COUNT(*) COUNT(1) COUNT(id)

通常得到相同结果。

二、举个例子

表中有三行:

idnameremark
1张三正常
2李四NULL
3王五正常

执行:

SELECT COUNT(*) AS c1, COUNT(1) AS c2, COUNT(id) AS c3, COUNT(remark) AS c4 FROM users;

结果是:

c1 = 3 c2 = 3 c3 = 3 c4 = 2

原因:

COUNT(*):统计所有行

COUNT(1)1永不为NULL,统计所有行

COUNT(id)id是主键,全部非NULL

COUNT(remark):忽略remark IS NULL的那一行

MySQL 中,COUNT(expr)统计的是表达式不为NULL的数量,而COUNT(*)统计行数。

三、哪个性能最好?

对 InnoDB 来说

通常结论是:

COUNT(*) = COUNT(1)

性能基本相同。

如果主键字段是:

id BIGINT PRIMARY KEY

那么:

COUNT(id)

结果通常也相同,但没有必要为了性能特意使用它。

实际开发中推荐:

SELECT COUNT(*) FROM users;

原因是:

语义最清晰

表达的是“统计行数”

MySQL 对它有明确的优化路径

不会因为字段是否允许NULL而产生误差

MySQL 官方说明,InnoDB 会按照当前事务可见性统计记录,并且对于没有额外WHEREGROUP BYCOUNT(*),通常会遍历可用的最小二级索引;没有二级索引时才扫描聚簇索引。

所以实际性能主要取决于:

是否有合适的WHERE条件

是否有合适的索引

索引大小

数据是否已经在 Buffer Pool 中

当前事务可见的数据量

表中数据规模

而不是取决于*1还是主键字段。

四、一个容易出错的场景:LEFT JOIN

考虑:

SELECT u.id, COUNT(*), COUNT(o.id) FROM users u LEFT JOIN orders o ON u.id = o.user_id GROUP BY u.id;

假设用户张三没有订单。

LEFT JOIN仍然会保留张三这一行,只是订单表字段全部为NULL

u.id o.id 1 NULL

因此:

COUNT(*) = 1 COUNT(o.id) = 0

这里两者含义不同:

COUNT(*):统计连接结果中的行数

COUNT(o.id):统计真正匹配到订单的数量

因此统计子表数量时,经常应该写:

COUNT(o.id)

而不是:

COUNT(*)

五、MyISAM 的特殊情况

如果使用 MyISAM,且查询是:

SELECT COUNT(*) FROM users;

没有WHERE条件时,MyISAM 可以利用存储的行数信息快速返回结果。

但 InnoDB 不保存一个可以直接返回的精确总行数,因为不同事务可能看到不同的数据版本。

不过现在绝大多数业务表使用 InnoDB,所以通常记住 InnoDB 的结论即可。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询