报表要数行数,同事写 count(1),隔壁写 count(*),还有人顺手 count 了一个允许为空的字段,两边数字对不上,争了半天。count 看着简单,几种写法差别真不小。
三种写法的区别
- count(*):统计行数,包括所有列都为空的记录,是标准的行数统计。
- count(1):同样是数行,1 只是常量,不读列值,多数数据库里和 count(*) 等价。
- count(字段):只统计该字段非 NULL 的行,字段为空的不计入,结果常比总行数少。
结果为什么对不上
把 count(*) 换成 count(某列) 之后数字变小,几乎都是那列有 NULL。统计用户数时,如果昵称允许为空,用 count(昵称) 就漏掉了没填的人。要数人数,用主键或直接 count(*) 更稳。
带条件一起数
select count(*) from orders where status = 1; select status, count(*) from orders group by status;要按维度分组就配 group by,select 里出现的非聚合列都得写进 group by,否则 MySQL 宽松模式能过、严格模式直接报错。过滤分组后的结果用 having,别用 where,后者在分组之前就生效了。
性能上留个心
count(*) 在有索引时,数据库会挑最小的索引来扫,通常不慢。大表还要去重时,count(distinct 列) 开销明显,可以考虑提前算好放缓存。分页列表别每次翻页都重新 count 全表,数据量大的站点这一条就能省掉不少压力。
别把 count 当求和用
count 只数行,想加总金额得用 sum,想数非空值也是 count,想数不同值的个数要加 distinct。三者混用是报表出错的常见来源,写完先拿一小批数据手工核对一遍。
- 判断提醒:只有确定要排除空值时才用 count(字段);数总行数一律 count(*),别为所谓优化写成 count(主键),可读性反而更差。