Appearance
COUNT(*) 和 COUNT(列) 到底差在哪
先说结论
COUNT(*)统计的是行数COUNT(列)统计的是该列非NULL的行数- 真正的区别首先是语义,不是性能玄学
一、最核心的区别就是 NULL
看下面这个表意就够了:
COUNT(*):这一行在不在COUNT(name):这一行的name有没有值
所以如果某列允许 NULL,两者结果天然可能不同。
这也是为什么很多统计 SQL 一上来就写 COUNT(id),但其实如果 id 本来就非空,它和 COUNT(*) 在结果上没有区别。
二、为什么很多人总拿性能说事
因为早些年不同数据库、不同版本、不同执行器实现下,确实会有一些细节差异。
但在 MySQL 里,日常业务真正更该先关心的是:
- 你的统计语义对不对
- 有没有 where 条件
- 有没有合适索引
- 是不是在扫太多数据
大多数慢统计问题,根因都不在“你用了 COUNT(*) 还是 COUNT(id)”。
三、什么时候应该优先写 COUNT(*)
当你就是想统计“满足条件的总行数”时,优先写 COUNT(*) 最清晰。
比如:
- 统计订单总数
- 统计当天注册用户数
- 统计某状态下的记录数
它表达最直接,也最不容易误导后面维护的人。
四、什么时候写 COUNT(列) 才有明确意义
当你就是想统计“这个字段有值的记录数”时,COUNT(列) 才更合适。
比如:
- 统计已填写手机号的用户数
- 统计有发货时间的订单数
- 统计有退款原因的记录数
这时候它表达的是业务语义,而不是性能技巧。
五、最容易踩的坑
1. 把 COUNT(id) 当成性能优化模板
如果 id 本来就非空,很多时候它只是换了种写法,并没有解决真正的统计成本问题。
2. 列允许 NULL 却误以为和 COUNT(*) 等价
这会直接导致统计结果偏差。
3. 统计慢了就只改 COUNT 写法
更应该先看:
- 过滤条件
- 索引命中
- 扫描范围
- 是否可以走汇总表或缓存
总结
COUNT(*) 和 COUNT(列) 首先是语义差异,不是优化口诀。想统计总行数就用 COUNT(*),想统计某列非空值就用 COUNT(列)。真正的性能问题,多半还是要回到条件、索引和扫描范围上解决。