count(*)是最准、最稳、最推荐的写法,语义清晰(统计所有行),innodb下性能不输count(1)或count(列名),myisam下可能更快;它不忽略null行,符合“统计行数”本意,且是sql92标准,兼容性最佳。

直接回答:COUNT(*) 是最准、最稳、最推荐的写法
别纠结 COUNT(1) 或 COUNT(id),除非你明确要统计某列非 NULL 的数量,否则一律用 COUNT(*)。它在语义上最清晰(统计所有行),在 InnoDB 下性能不输任何变体,在 MyISAM 下甚至可能更快;更重要的是,它不会因字段允许 NULL 而漏计——这是 COUNT(列名) 最容易踩的坑。
COUNT(列名) 会忽略 NULL 行,不是“统计行数”的等价替代
当你写 COUNT(name),MySQL 实际干的是:逐行读取 name 字段值,跳过所有 name IS NULL 的记录,只对非 NULL 值累加。这和“表里有多少条数据”是两回事。
- 如果该列有 100 行,其中 5 行
name为NULL,COUNT(name)返回 95,但COUNT(*)返回 100 - 即使该列被定义为
NOT NULL,语义上仍是“检查该列”,多了一层判断开销(虽小但存在) -
COUNT(主键)看似安全,但一旦主键被误设为可空(极少见但可能),结果就不可靠;而COUNT(*)永远只看行存在与否
InnoDB 下 COUNT(*) 和 COUNT(1) 性能几乎一样,但 COUNT(*) 更“省心”
MySQL 8.0.13+ 对无 WHERE 的 COUNT(*) 做了扫表优化;InnoDB 引擎内部把 COUNT(*) 和 COUNT(1) 当作同一类操作处理,server 层不额外解析表达式。但关键区别在于:
-
COUNT(*)是 SQL92 标准,所有 MySQL 版本、所有存储引擎都按统一逻辑解释,无需担心兼容性漂移 -
COUNT(1)需要 server 层先确认常量 1 的类型和非空性,虽然耗时微乎其微,但属于“多一次判断” - 某些旧版或定制版 MySQL(如部分阿里云 RDS 分支)曾对
COUNT(*)做过深度内联优化,COUNT(1)反而没命中——这种细节你没法靠文档穷举
带 WHERE 条件时,三者执行路径完全一致,选哪个都不影响性能
只要 SQL 中含 WHERE(比如 SELECT COUNT(*) FROM user WHERE status = 1),MySQL 就必须走索引扫描或全表扫描来过滤行,此时 COUNT(*)、COUNT(1)、COUNT(id) 的执行计划完全相同——因为最终都得把满足条件的每一行“数一遍”。这时候:
- 别幻想
COUNT(1)会比COUNT(*)快,explain 结果里它们的rows和Extra字段一模一样 - 也别用
COUNT(列名)试图“借力索引”,除非你真需要排除该列 NULL 值——否则只是徒增语义歧义 - 真正影响速度的是 WHERE 条件能否走索引、是否触发 filesort,跟 COUNT 里填什么无关
最常被忽略的一点:很多人以为 COUNT(*) 会“查出所有字段再丢弃”,其实它全程只读行头(record header),根本不访问具体列数据——这个底层行为,只有 COUNT(*) 能稳定依赖。











