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获取精确行数。