MySQL 中 COUNT 函数的用法与区别详解
COUNT() 是 MySQL 中用于统计记录行数的聚合函数,但其参数不同(如 COUNT(*)、COUNT(1)、COUNT(列名))时,行为和性能存在差异。理解这些差异有助于写出更高效、准确的统计语句。
COUNT 函数的三种常见用法
1. COUNT(*)
- 作用:统计所有记录的行数,包括
NULL 值(无论字段是否为 NULL,只要行存在就计数)。
- 特点:
- 不忽略任何行,包括包含
NULL 的行。
- InnoDB 引擎对
COUNT(*) 进行了优化,会自动选择最小的索引(非主键索引优先)来加速统计,性能较好。
示例:
1 2
| SELECT COUNT(*) FROM doc;
|
2. COUNT(1)
- 作用:统计所有记录的行数,原理与
COUNT(*) 类似(用常量 1 代替字段,只要行存在就计数)。
- 特点:
- 同样包含
NULL 值的行(因为 1 是常量,永远非 NULL)。
- 在 InnoDB 中,
COUNT(1) 与 COUNT(*) 性能几乎一致,优化方式相同(优先使用最小索引)。
示例:
1 2
| SELECT COUNT(1) FROM doc;
|
3. COUNT(列名)
- 作用:统计指定列中非
NULL 值的行数(自动忽略 NULL 值)。
- 特点:
- 仅计数该列值不为
NULL 的行(若列允许 NULL,结果可能小于总行数)。
- 若该列上有索引,会使用索引加速统计;否则会全表扫描,性能可能较差。
示例:
1 2
| SELECT COUNT(source) FROM doc;
|
核心区别对比
| 用法 |
计数范围 |
是否忽略 NULL 值 |
性能优化(InnoDB) |
适用场景 |
COUNT(*) |
所有行(包括 NULL 行) |
不忽略 |
自动选择最小索引(非主键优先),性能优 |
统计总记录数 |
COUNT(1) |
所有行(包括 NULL 行) |
不忽略 |
与 COUNT(*) 一致,性能几乎无差异 |
统计总记录数(写法习惯差异) |
COUNT(列名) |
指定列非 NULL 的行 |
忽略 |
依赖列是否有索引,无索引时性能较差 |
统计某列非空值的行数 |
性能对比与最佳实践
COUNT(\*) vs COUNT(1):
- 在 InnoDB 中,两者性能几乎无差异(优化逻辑相同)。
- 推荐使用
COUNT(*),因为它是 SQL 标准中统计总行数的规范写法,可读性更高。
COUNT(\*) vs COUNT(主键):
COUNT(主键) 会统计主键列非 NULL 的行数(主键永远非 NULL,结果与 COUNT(*) 一致)。
- 但
COUNT(*) 会选择更小的非主键索引,而 COUNT(主键) 强制使用主键索引(可能更大),因此 COUNT(*) 性能更优。
COUNT(列名) 的注意事项:
- 若列允许
NULL,结果不等于总行数,需确认业务是否需要忽略 NULL。
- 为提升性能,建议在统计的列上创建索引(尤其是大表)。
- 避免
COUNT(1) 与 COUNT(\*) 的误区:
- 网上传言 “
COUNT(1) 比 COUNT(*) 快” 是错误的,InnoDB 对两者的优化完全一致。
COUNT(*) 不会像传言那样 “展开所有字段”,而是直接统计行数,与字段数量无关。
示例分析
1 2
| SELECT COUNT(*), COUNT(1), COUNT(source) FROM doc;
|
COUNT(*) 和 COUNT(1) 均返回 188,说明表中共有 188 行(包括 source 列为 NULL 的行)。
COUNT(source) 返回 2,说明 source 列中只有 2 行的值非 NULL,其余 186 行为 NULL