count(*)的实现方式:
在不同的MySQL引擎中,count()实现的方式不同。
· MyISAM引擎中把一个表的总行数直接存在了磁盘上,执行count() 的时候直接返回这个数,效率很高;(不支持事务)
· 而InnoDB引擎,执行count(*)的时候,需要把数据一行一行的从引擎读出来,然后累计计数;(因为MVCC的实现,应该返回多少行是不确定的(自己能读到自己事务的未提交记录,而不能读到别人事务的未提交记录))
但是InnoDB在执行count()是做了优化的。
InnoDB是索引组织表,主键索引树的叶子节点是数据,而普通索引树的叶子节点是主键值。所以,普通索引树比主键索引树小很多。对于count()这个操作,遍历哪个索引树得到的结果逻辑上是一样的,所以MySQL优化器会选择最小的那棵树来遍历。
在保证逻辑正确的前提下,尽量减少扫描的数据量,是数据库系统设计的通用法则之一。
count() 对于返回的结果集,一行行的判断,如果count函数的参数不是NULL,累计值就加1,最后返回累加值。
server层要什么,InnoDB就返回什么。(就是SQL语句要什么字段,InnoDB就返回什么字段)
count(字段) 则表示返回满足条件的数据行里面,字段值不为NULL的总个数。
count(主键id): InnoDB引擎会遍历整张表,把每一行的id取出来,返回给server层。server层拿到id后,判断是不可能为空的,就按行累加。
count(1): InnoDB引擎会遍历整张表,但不取值。server层对于返回的每一行,放一个数字"1"进去,判断是不可能为空的,按行累加。
count(字段):
1.如果字段定义为not null的话,一行行的从记录里面读出这个字段,判断不能为null,按行累加;
2.如果字段定义允许为null,执行的时候判断到有可能是null,还要把值取出来再判断一下,不是null才累加。
count(): 这个是个特例,并不会全部字段取出来返回,做了特殊的优化,不取值。count()肯定不是null,直接按行累加。
结果: count(*)≈count(1)>count(主键id)>count(字段)。