以下是 Oracle 中 COUNT函数的详细解析及对比,包含执行原理、性能差异和最佳实践。
一、执行原理
1. COUNT(expr) —— 统计非 NULL 值
作用:返回表达式中 不为 NULL 的行数。
SELECT COUNT(commission_pct) FROM employees;
•原理:遍历 commission_pct列,跳过所有 NULL值,只计算有值的行。
•注意:如果 expr涉及多列(如 COUNT(col1 + col2)),只要其中一列为 NULL,整个表达式结果即为 NULL,该行不计入统计。
2. COUNT(DISTINCT expr ) —— 统计唯一非 NULL 组合
作用:返回去重后、且 不为 NULL 的值的组合数量(Oracle 支持多列去重)。
-- 单列去重
SELECT COUNT(DISTINCT department_id) FROM employees;
-- 多列组合去重 (Oracle 特有)
SELECT COUNT(DISTINCT department_id || '-' || job_id) FROM
employees;
-- 或
SELECT COUNT(DISTINCT department_id, job_id) FROM employees; -- 12c+ 支持标准语法
•原理:先对 expr组合进行去重,再排除掉结果为 NULL的组合,最后计数。
•注意:如果 department_id和 job_id都为 NULL,该组合会被忽略;如果其中一个为 NULL,该组合依然参与去重计数。
3. COUNT(*) vs COUNT(1) —— 统计所有行
作用:两者都返回表中的总行数(包含 NULL 行)。
SELECT COUNT(*) FROM employees;
SELECT COUNT(1) FROM employees;
核心区别与执行原理
特性 | COUNT(*) | COUNT(1) |
|---|---|---|
含义 | 统计所有行数 | 对每一行计算常量 |
NULL 处理 | 包含 NULL 行 | 包含 NULL 行(因为 |
Oracle 优化 | 最优。Oracle 对其进行了特殊优化,直接读取行数,无需计算表达式。 | 优化器通常会将其优化为 |
索引利用 | 若表有主键或任意非空索引,可仅扫描索引(INDEX FAST FULL SCAN)。 | 同左,优化后行为一致。 |
结论:COUNT(*)是 SQL 标准中统计行数的标准写法,也是 Oracle 官方推荐的最佳实践。
综合对比总结、
函数 | 是否计 NULL 行 | 是否去重 | 典型用途 |
|---|---|---|---|
COUNT()* | 是 | 否 | 统计全表或分组的总行数(最常用) |
COUNT(1) | 是 | 否 | 统计总行数(老习惯,建议改用 |
COUNT(expr) | 否 | 否 | 统计某列有值的数量(如统计有邮箱的员工数) |
COUNT(DISTINCT expr) | 否 | 是 | 统计某列不重复值的数量(如统计有多少个部门) |
二、性能排序(通常情况下)
COUNT(*) ≈ COUNT(1)> COUNT(主键)> COUNT(普通列)
•原因:COUNT(*)不需要读取具体的列数据,只需找到一条存在的记录即可(利用索引最快)。COUNT(列)需要读取该列的数据块,I/O 成本更高。
三、最佳实践建议
1.统计行数:无条件使用 COUNT(*)。
2.统计某列非空值:使用 COUNT(column_name)。
3.统计唯一值:使用 COUNT(DISTINCT column_name)。
4.多列 DISTINCT 的陷阱
COUNT(DISTINCT col1, col2)统计的是 (col1, col2)组合的唯一性,而不是分别统计两列的唯一值。
-- 错误:想统计两列各自去重后的总数
SELECT COUNT(DISTINCT col1), COUNT(DISTINCT col2) FROM t;
-- 正确:必须分开写