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(*)

发表评论

邮箱地址不会被公开。 必填项已用*标注