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