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 不支持存储精确行数,必须扫描),优化手段:
- 维护计数:单独一张计数表,事务里同步更新(或 Redis 计数,注意一致性);
- 近似统计:
SHOW TABLE STATUS的 rows 是估算值;或information_schema估算; - 走二级索引:MySQL 会选最小的索引扫描(count(*) 时优化器挑占用空间最小的索引树);
- 分页/列表场景别 count 全表,业务上减少这类查询。
加分点
- MyISAM 会存储行数所以 count(*) 快,但 MyISAM 有表锁,已不推荐;
- InnoDB 需要 MVCC 可见性判断,所以不能直接读存储的行数;
- 面试答法:"先讲语义区别,再说 MySQL 中 count(*) 和 count(1) 等价且最快,count(字段) 要判 NULL 更慢,最后说大表别 count 要维护计数"。
一句话总结
count(*) 统计所有行、count(1) 等价、count(字段) 只计非 NULL;MySQL 中 count(*)≈count(1) 最快,count(字段) 更慢;大表 count 要避免全表扫描,改用计数表/缓存/估算。