mysql如何统计行数_mysql count函数操作说明

来源:这里教程网 时间:2026-02-28 20:44:32 作者:

count(*)、count(1)、count(字段) 到底有什么区别?

三者统计逻辑不同,但

count(*)
count(1)
在 InnoDB 下行为完全一致,都是统计满足 WHERE 条件的所有行(含全 NULL 行);而
count(字段)
会跳过该字段值为
NULL
的行。

count(*)
:语义最清晰,MySQL 优化器会自动选择成本最低的索引(如主键)遍历计数,不依赖字段是否可空
count(1)
:本质是常量表达式,和
count(*)
执行计划、性能无差别,纯属写法偏好
count(age)
:只统计
age IS NOT NULL
的行,若该字段大量为 NULL,结果会明显小于
count(*)

为什么加了索引,count(*) 还很慢?

因为 InnoDB 引擎下,

count(*)
不像 MyISAM 那样直接读取表元数据中的“行数缓存”,而是必须扫描索引树——哪怕只是扫主键索引,百万级数据仍需 IO 和遍历开销。

有主键时,MySQL 优先用主键索引(
type=index
),比全表扫描快,但仍是 O(n)
没有主键、只有普通索引时,可能选最小的非空索引,但若索引列允许 NULL,部分版本可能退化为全表扫描 千万级大表慎用
count(*)
实时查总数,考虑用缓存或异步更新的统计表替代

统计去重数或带条件的行数,怎么写才不出错?

别硬套

count()
去实现条件计数,容易漏 NULL 或逻辑翻车。

要统计「年龄大于 25 的人数」:直接用
count(*)
+
WHERE age > 25
,别写
count(IF(age > 25, 1, NULL))
—— 多余且易错
要统计「不同部门数量」:用
count(DISTINCT department)
,注意该写法自动忽略
department IS NULL
的行
要统计「有邮箱且邮箱不重复的人数」:
count(DISTINCT c_email)
即可,无需额外
WHERE c_email IS NOT NULL
DISTINCT
本身已跳过 NULL)

GROUP BY 配合 count() 时最容易踩的坑

常见错误是误以为

count(*)
会按分组“过滤掉 NULL”,其实它统计的是每组内所有行,包括该组中某列为 NULL 的记录。

比如
SELECT gender, count(*) FROM users GROUP BY gender
,如果
gender
有 NULL 值,就会单独产生一行
NULL | 12
想排除 NULL 分组?得显式写
WHERE gender IS NOT NULL
想统计每组里「name 不为空的人数」?用
count(name)
,不是
count(*)
—— 后者统计整组行数,前者只算
name
非空的行
实际开发中,最常被忽略的是:InnoDB 的
count(*)
没有“瞬时快照”属性,它反映的是当前事务隔离级别下可见的行数,RR 级别下可能因 MVCC 读到旧版本导致计数偏少——这不是 bug,是设计使然。

相关推荐