count(*)的执行速度会伴随着整个表的增大而越来越慢,而且在不同的引擎之中,count(*)具有不同的实现方式
比如MyISam中:将一个表的总数存在了磁盘上,在查询的时候直接返回这个数值即可
在InnoDB中,需要一行行的读出来进行累计,为何InnoDB会选择一种看起来就比MyISAM慢的方式去实现呢,而不是直接将表存起来
因为,在InnoDB中存在事务,使用了多版本并发控制去实现的,InnoDB应该返回多少行,是不确定的
假设具有10000条记录,有三个并行的会话
从上面可以看出,如果三个会话同时查询表的总行数,结果是不一样的
可重复读是其默认的隔离级别,在代码中可以通过多版本控制的
只能一行行的读取计数
但是往往速度很快
因为InnoDB中,采用了索引组织表,主键索引树叶子节点的数据是数据,普通索引树的叶子节点是主键值,于是遍历普通索引树所需要的扫描数据量更少,MySQL优化器会找到最小的那棵树来进行遍历,这样看来 比MyISAM更快,因为在where查询中,MyISAM则是傻不愣登的直接一行行的扫描
虽然直接show table staus 命令的话,也可以获取到一个TABLE_Rows来显示这个表有多少行,但这个行数是采样估算的,并不一定准确
最后说一下
不同的count用法
在count中可以使用 count(*),count(主键id),count(1)等不同的用法的性能,之间的差异在于count()是一个聚合函数,对于返回的结果集,会一行行的判断,如果count的函数不是NULL,累计值加一,不然不加,最后返回累计值
所以 count(*) count(1) count(主键)都是返回的满足条件的结果集的总行数,但是count(字段),则是表示返回满足条件的数据行中,参数不为NULL的总个数
首先亮出来总结
1.Server层只给需要的列表
2.InnoDB只给必要的值
3.优化器只优化了count(*)的取值,其他优化没有做
对于count(主键id) InnoDB会遍历整张表,每一行的id都取出来,Server拿到id后,按行累加
对于count((1) 也会遍历整个表,但是不去值,Server层对于返回的每一行,都放一个1进去,按行累加
而对于count(字段)来说,如果字段是not null的话,会一行行的读出字段,按行累加
如果没有定义not null的话,会判断是否是null,来进行累加
但是count(*)除外啊,count(*)并不能为null,按行累加
总结下来 ,效率为
count(字段)<count(id)<count(1)约等于count(*)