MySQL的count(expr)
函数选择指南
1. 背景知识
- 文章基于MySQL 8.0.30,使用InnoDB和MyISAM引擎。
count(expr)
: MySQL聚合函数,用于统计列值或表行数。- 统计列值: 只计非NULL值。
- 统计表行数: 不区分NULL与否。
2. 存储引擎差异
- MyISAM: 表定义、数据、索引分别存储,行数存储于磁盘。
- InnoDB: 所有内容存储于单一文件,无预先存储的行数。
3. count(*)
行为
- MyISAM: 直接从磁盘读取行数,无
where
条件时高效。 - InnoDB: 无预先存储行数,需逐行累加。
4. MVCC与事务隔离级别
- InnoDB支持事务,使用MVCC实现可重复读,影响
count(*)
行为。
5. 性能分析
- InnoDB优化:选择最小索引树遍历,减少数据量,提升性能。
6. count(expr)
函数详解
count(主键)
: 遍历表,返回主键值,统计总数。count(1)
: 遍历表,Server层每行放置数字1,统计总数。count(非主键字段)
: 统计字段值不为NULL的总数,可能少于实际行数。
7. 源码分析
- 实现: C++,
item_sum.cc
文件。 count(*)
: 内部视为count(0)
。count(1)
: 直接处理为longlong
类型1。count(字段名)
: 处理为字段类型Item_field
。
8. 总结
- 效率排序:
count(非主键字段) < count(主键) < count(1) ≈ count(*)
。 - 推荐: 使用
count(*)
,优化器选择最小索引树。 count(*)
: 包含NULL值的行数。count(非主键字段)
: 不含NULL值的行数。
9. show table status
的准确性
- 误差率: 40% ~ 50%,不推荐用于精确统计。
10. 特殊情况
- InnoDB单索引:
count(*)
和count(1)
通过主键索引统计。 - InnoDB多索引: 优化器选择最小索引树。
参考文献
- MySQL-server GitHub源码
- MySQL 8.0官方文档
- MySQL 8.0 MyISAM引擎官方文档
- MySQL 8.0 聚合函数官方文档
建议
- 优先使用
count(*)
,利用MySQL优化器。 - 考虑NULL值情况,选择合适的
count(expr)
变体。 - 避免使用
show table status
获取精确行数。