count(*)在不同引擎中的实现不同。在MyISAM中是直接保存了一个不带where条件的计数结果数值,会比较快。在InnoDB中需要每条取出计数,因为InnoDB多版本并发控制MVCC的原因,返回多少行不是唯一确定的,所以无法直接保存数值。
注意,命令show table status的结果也有一个TABLE_ROWS显示当前表有多少行,但是这个结果是索引采样计算的,不准,所以不能直接使用这个值来作为表的行数。
InnoDB对count(*)的优化
InnoDB中普通索引的叶子节点由于不存储数据只存储主键值,所以比主键索引小很多。对于count(*)来说,遍历哪个索引树得到的结果逻辑上都是一样的,因此MySQL会找一棵最小的树来遍历,依次来减少IO开销。
count(*)的替代方案
用缓存保存技术
在redis中维护一个表的总行数。
缺点:缓存系统有可能丢失更新。2)由于插入数据并redis加1,和查询redis是在两个并发线程中,所以会导致查询到的count值是不准确的情况。
在数据库中保存计数
不同count字段的性能
结论:count(*) >= count(1) > count(主键id) > count(字段)
count(字段):遍历整张表,需要取值,判断 字段 != null,按行累加;
count(id) :遍历整张表,需要取ID,判断 id !=null,按行累加;
count(1) : 遍历整张表,【不需要】取值,返回的每一行放一个数字1,按行累加;
count() : 【不需要取字段】,count(),按行累加;
因为count(*) 和 count(1) 不取字段值,减少往 server层的数据返回,所以比其他count(字段)要返回值的【性能】较好;
