欢迎光临
我们一直在努力

Mysql:count(1)和count(*)和count(主键字段)有什么区别?

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

1. COUNT(*)

SELECT COUNT(*)
FROM users;

表示:

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

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

2. COUNT(1)

SELECT COUNT(1)
FROM users;

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

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

每行 -> 计算出 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 会按照当前事务可见性统计记录,并且对于没有额外 WHERE、GROUP BY 的 COUNT(*),通常会遍历可用的最小二级索引;没有二级索引时才扫描聚簇索引。

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

是否有合适的 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 的结论即可。

赞(0)
未经允许不得转载:171主机测评 » Mysql:count(1)和count(*)和count(主键字段)有什么区别?
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址