这是一个非常经典的SQL面试题和知识点。COUNT(*) 和 COUNT(column_name) 的核心区别在于它们的计数规则。
简单来说:
COUNT(*):统计的是结果集的行数,不管这一行里的字段值具体是什么(即使是NULL或空值)。COUNT(column_name):统计的是指定字段非空值(NOT NULL)的数量。
详细对比与举例
我们通过一个例子来彻底理解。假设有一张名为 employees 的员工表:
| id | name | department | salary |
|---|---|---|---|
| 1 | 张三 | 技术部 | 10000 |
| 2 | 李四 | NULL | 8000 |
| 3 | 王五 | 销售部 | NULL |
| 4 | NULL | 财务部 | 12000 |
现在我们来执行不同的 COUNT 语句:
1. COUNT(*)
它关心的是“有多少条记录”。
SELECT COUNT(*) AS total_count FROM employees;
结果:4
解释: 表里总共有4行数据,COUNT(*) 会把它们全部数出来,完全不关心具体字段的内容。
2. COUNT(column_name)
它关心的是“这个字段有多少个有效值(非NULL)”。
-
统计
name字段:SELECT COUNT(name) AS name_count FROM employees;结果:
3
解释:name字段有4条记录,但其中id=4的记录name为NULL,所以不计数。只有“张三”、“李四”、“王五”这3个非空值被计数。 -
统计
department字段:SELECT COUNT(department) AS dept_count FROM employees;结果:
3
解释:department字段中,id=2的记录为NULL,所以只有3个非空值。 -
统计
salary字段:SELECT COUNT(salary) AS salary_count FROM employees;结果:
3
解释:salary字段中,id=3的记录为NULL,所以只有3个非空值。
核心区别总结表
| 特性 | COUNT(*) | COUNT(column_name) |
|---|---|---|
| 计数目标 | 结果集的行数 | 指定列的非空值数量 |
| 对 NULL 的处理 | 包含值为 NULL 的行 | 排除值为 NULL 的单元格 |
| 性能(常见情况) | 在现代主流数据库(如 MySQL InnoDB, PostgreSQL)中,性能最优。优化器会选择最快的索引来统计行数,甚至直接使用表的元数据。 | 通常需要读取该列的实际数据来判断是否为空,如果该列没有索引,可能会比 COUNT(*) 稍慢。 |
| 使用场景 | 当你需要知道总共有多少条记录时。例如,“计算订单总数”。 | 当你需要知道某个特定字段有效数据的数量时。例如,“计算已分配部门的员工数”。 |
重要补充:COUNT(1) 是什么?
COUNT(1) 中的 1 是一个常量值,它的含义是“对每一行,都返回一个常数值1”。它的行为与 COUNT(*) 完全相同。
COUNT(1):统计所有返回1的行数。因为每一行都会返回1,所以最终也是统计总行数。- 性能:在现代数据库优化器中,
COUNT(1)和COUNT(*)的执行效率是没有区别的。优化器会对它们做同样的优化。很多DBA和开发者习惯使用COUNT(1),但SQL标准推荐使用COUNT(*),因为它更清晰地表达了“计数”的意图。
结论
- 想要总行数,毫不犹豫地用
COUNT(*)。它最准确,性能也好。 - 想要统计某个字段的有效值个数(排除NULL),就用
COUNT(column_name)。 - 不要担心
COUNT(*)的性能问题,数据库已经对此做了充分优化。
630

被折叠的 条评论
为什么被折叠?



