count(*)的实现方式
MyISAM引擎把一个表的总行数存在了磁盘上,执行count(*)的时候直接返回这个数,效率很高;
InnoDB引擎执行count(*)的时候,需要把数据一行一行地从引擎里面读出来,然后累积计数。
上述说明是在没有where条件的时候,如果加了where条件的话,MyISAM表也不能返回得这么快。
InnoDB引擎支持事务,可重复读是它的默认隔离级别,在代码上是通过多版本并发控制(MVCC)实现的,每一行记录都要判断自己是否对这个会话可见,所以无法像MyISAM引擎一样,直接记录一个总行数,当需要的时候返回这个值。如下图所示,返回的总行数并不一样。
InnoDB是索引组织表,主键索引树的叶子节点是数据,而普通索引树的叶子节点是主键值,所以,普通索引树比主键索引树小很多。而对于count(*)这样的操作,遍历哪个索引树得到的结果逻辑上都是一样的,因此,MySQL优化器会找到最小的那棵树来遍历。
show table status命令显示的行数并不准确,不能直接使用。官方文档说误差可能达到40%-50%。
可以采用自己记录总行数的思路,比如把总行数记录到redis或者MySQL中,但是把计数放到redis中,不能够保证计数和MySQL表里的数据精确一致,因为这是两个不同的存储构成的系统,不支持分布式事务,无法拿到精确一致的视图;而把计数值放在MySQL中,就解决了一致性视图的问题。
不同count的用法
count()是一个聚合函数,对返回的结果集,一行行的判断,如果count函数的参数不是NULL,累计值就加1,否则不加,最后返回这个累计值。所以count(*)、count(主键)、count(1)都表示返回满足条件的结果集总行数,而count(字段)则表示返回满足条件的数据行里面,参数“字段”不为NULL的总个数。
按照效率排序:count(字段)<count(主键)<count(1)≈count(*)
正文止。
感兴趣的朋友,欢迎关注我的公众号哈,公众号上已经集成了AI大模型,大家可以过来聊天、问问题了