count()和count(1)统计所有行(含NULL),执行一致;count(字段)跳过该字段为NULL的行;InnoDB中count()需遍历索引,无行数缓存,大表慎用。

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 或逻辑翻车。
PHP是一种功能强大的网络程序设计语言,而且易学易用,移植性和可扩展性也都非常优秀,本书将为读者详细介绍PHP编程。 全书分为预备篇、开始篇和加速篇三大部分,共9章。预备篇主要介绍一些学习PHP语言的预备知识以及PHP运行平台的架设;开始篇则较为详细地向读者介绍PKP语言的基本语法和常用函数,以及用PHP如何对MySQL数据库进行操作;加速篇则通过对典型实例的介绍来使读者全面掌握PHP。 本书
- 要统计「年龄大于 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非空的行
count(*) 没有“瞬时快照”属性,它反映的是当前事务隔离级别下可见的行数,RR 级别下可能因 MVCC 读到旧版本导致计数偏少——这不是 bug,是设计使然。









