Skip to content

P29 count(星)、count(1)、count(字段) 谁更快?有什么区别 ​

面试题:count(*)、count(1)、count(字段) 有什么区别?哪个性能最好?

1. 语义区别 ​

写法统计内容
count(*)统计所有行数,不做字段取值,不忽略任何行
count(1)每行取常量 1 计数,等价于 count(*),不忽略任何行
count(字段)统计该字段非 NULL 的行数,NULL 不计数

注意:count(字段) 会忽略 NULL,如果业务语义是"统计所有记录",用它可能数错。

2. 性能对比 ​

结论:count(*) ≈ count(1) > count(字段)(在 MySQL 中)

原因:

  • MySQL 8.0 中 count(*) 被优化器专门优化,直接数记录数,不取任何列数据;
  • count(1) 也被优化成类似 count(*) 的计数(8.0 后二者基本等价);
  • count(字段) 要判断字段是否为 NULL,还可能要读二级索引/回表取字段值,所以更慢;
  • 用 count(字段) 且字段没索引,需要遍历整张表的主键/行。

网络上"count(1) 比 count(*) 快"的说法是旧版本/其他数据库的经验,MySQL 里二者等价,选 count(*) 最规范。

3. 大表 count 优化 ​

无论哪种写法,全表 count 都很慢(InnoDB 不支持存储精确行数,必须扫描),优化手段:

  1. 维护计数:单独一张计数表,事务里同步更新(或 Redis 计数,注意一致性);
  2. 近似统计:SHOW TABLE STATUS 的 rows 是估算值;或 information_schema 估算;
  3. 走二级索引:MySQL 会选最小的索引扫描(count(*) 时优化器挑占用空间最小的索引树);
  4. 分页/列表场景别 count 全表,业务上减少这类查询。

加分点 ​

  • MyISAM 会存储行数所以 count(*) 快,但 MyISAM 有表锁,已不推荐;
  • InnoDB 需要 MVCC 可见性判断,所以不能直接读存储的行数;
  • 面试答法:"先讲语义区别,再说 MySQL 中 count(*) 和 count(1) 等价且最快,count(字段) 要判 NULL 更慢,最后说大表别 count 要维护计数"。

一句话总结 ​

count(*) 统计所有行、count(1) 等价、count(字段) 只计非 NULL;MySQL 中 count(*)≈count(1) 最快,count(字段) 更慢;大表 count 要避免全表扫描,改用计数表/缓存/估算。

基于 VitePress 重建