count()配合where是最直接的条件统计方式,例如select count() from users where age > 25,mysql先执行where过滤再计数,可利用索引加速;count(*)统计所有匹配行,而count(列名)会忽略该列为null的行,易导致结果偏小。

COUNT(*) 配合 WHERE 是最直接的条件统计方式
想统计“年龄大于 25 的用户数”,直接写 SELECT COUNT(*) FROM users WHERE age > 25 就行。MySQL 会先执行 WHERE 过滤,再对结果集行数计数——不是全表扫描后判断,而是利用索引(如果 age 有索引)快速定位符合条件的行,再统计数量。
注意:这里用 COUNT(*) 而不是 COUNT(age),因为目标是“记录条数”,不是“age 字段非 NULL 的条数”。如果 age 列本身允许 NULL,而你又漏写了 WHERE,COUNT(age) 会把 NULL 行自动剔除,导致结果偏小。
需要多条件或分支统计时,用 COUNT + CASE WHEN
比如统计“已发货订单数”和“待发货订单数”在一个查询里,不能靠多个 WHERE,得用条件聚合:
SELECT COUNT(CASE WHEN status = 'Shipped' THEN 1 END) AS shipped_count, COUNT(CASE WHEN status = 'Pending' THEN 1 END) AS pending_count FROM orders;
关键点:
-
CASE WHEN ... THEN 1 END中的ELSE被省略,等价于ELSE NULL;而COUNT()会忽略NULL,所以只计满足条件的行 - 不要写
COUNT(1)或COUNT(*)在CASE里——COUNT(*)在CASE分支中语法不合法,COUNT(1)也没意义,它永远返回 1 - 如果字段可能为 NULL(比如
status是 NULL),且你想单独统计 NULL 行,得显式写CASE WHEN status IS NULL THEN 1
COUNT(DISTINCT ...) 用于去重后计数,但 WHERE 仍要前置
比如“统计不同城市的用户数”,但只算活跃用户(is_active = 1):
SELECT COUNT(DISTINCT city) FROM users WHERE is_active = 1;
这里 WHERE 必须写在 COUNT(DISTINCT ...) 外面。如果错误地写成 COUNT(DISTINCT city WHERE is_active = 1),语法报错:ERROR 1064 (42000): You have an error in your SQL syntax。
另外注意:COUNT(DISTINCT city) 会自动跳过 city IS NULL 的行——哪怕这些行满足 WHERE 条件,NULL 值也不参与去重计数。
性能和 NULL 处理是最容易被忽略的两个点
很多人以为 COUNT(*) 和 COUNT(1) 完全一样,实际在 InnoDB 表上,MySQL 8.0+ 优化器确实常将两者等价处理;但如果你用的是老版本,或者表没主键、没合适索引,COUNT(*) 可能触发全表扫描,而 COUNT(主键) 有时能走索引覆盖,更快。更隐蔽的问题是 NULL:只要用了 COUNT(列名),该列任意一行是 NULL,就直接不算——这个行为不会报错,也不会警告,结果就是少了几条,查半天才发现是数据里混了 NULL。











