1. 系统版本
MySQL 5.7.25,Ubuntu 16.04
2. count()函数
2.1 count(*)
count(*)用于计算数据表的行数。
2.1.1 MyISAM实现方式
MyISAM将数据表的总行数存储在磁盘,当有sql语句调用count(*)时,MyISAM能直接返回表的总行数。但是,当sql语句有WHERE
语句限制查询行数时,MyISAM要重新算符合WHERE语句的数据表的行数,并不能直接返回行数。
2.1.2 InnoDB实现方式
InnoDB的隔离级别是可重复读,支持MVCC,其数据表的行数无法预先确定,只能通过执行查询的时候才能确定当时的行数,故InnoDB无法预先存储数据表的行数。对于每个count(*),InnoDB需要重新计算数据表的行数。
与此同时,MySQL对count(*)进行了优化。
2.2 count(1)、count(主键)以及count(column)的区别
本节仅针对InnoDB引擎的情况下开展。
2.2.1 count(1)
InnoDB会遍历整张表,但不获取具体的值,server层每获取一行,判断不为空的,就+1。可等价为返回数据表总行数。
2.2.2 count(主键)
InnoDB会遍历整张表,并获取每一行的主键,server层每获取一个主键,判断不为空,就+1。可等价为返回数据表总行数。
2.2.3 count(column)
该形式下的函数返回该字段不为null的行数。
InnoDB会判断字段定义是否为not null:
若为not null,则遍历整张表,获取每一行所对应的字段值,返回给server层,server层进行累加,每次累加值为1;
若字段可以为空,则依次取出每一行对应的字段后,server层需要额外判断取出的值是否为空,若不为空,则+1。
3. 执行效率
使用InnoDB的前提下,执行效率如下:
count(*)≈count(1)>count(主键)>count(1)