count()和count(1)以及count(列名)的区别

根据Mysql官方文档的说法:

 

count()和count(1)以及count(列名)的区别

There is performance difference(在性能上没有差别)

也就是说在InnoDB引擎上,count(*)和count(1)在性能上是一样的

再来说下count(列名):

count(列名)统计的是该列上不为null的数据

有这么一个表

count()和count(1)以及count(列名)的区别

 

在列[sex]上不为空的记录数有6条,执行select count(sex) from `user`; 看下结果

 count()和count(1)以及count(列名)的区别

可见count(列名)只统计不为null的数据记录数

 

不同的数据库引擎之间count(*)的执行差别:

  • MyIsAM:mysiam数据库引擎是表锁,在同一张表上的操作不会并发进行,所以myisam做了个简单的优化,直接把表的总行数单独记录下来,当遇到count(*) 操作时,直接返回这个值,前提是不带where查询条件
  • InnoDB:对于InnoDB来说,就不能做这种缓存操作了,因为InnoDB支持事务,其中大部分操作都是行级锁,所以可能表的行数可能会被并发修改,那么缓存记录下来的总行数就不准确了。但是,InnoDB还是针对COUNT(*)语句做了些优化的。在InnoDB中,使用COUNT(*)查询行数的时候,不可避免的要进行扫表了,那么,就可以在扫表过程中下功夫来优化效率了。从MySQL 8.0.13开始,针对InnoDB的SELECT COUNT(*) FROM tbl_name语句,确实在扫表的过程中做了一些优化。前提是查询语句中不包含WHERE或GROUP BY等条件。我们知道,COUNT(*)的目的只是为了统计总行数,所以,他根本不关心自己查到的具体值,所以,他如果能够在扫表的过程中,选择一个成本较低的索引进行的话,那就可以大大节省时间。我们知道,InnoDB中索引分为聚簇索引(主键索引)和非聚簇索引(非主键索引),聚簇索引的叶子节点中保存的是整行记录,而非聚簇索引的叶子节点中保存的是该行记录的主键的值。所以,相比之下,非聚簇索引要比聚簇索引小很多,所以MySQL会优先选择最小的非聚簇索引来扫表。所以,当我们建表的时候,除了主键索引以外,创建一个非主键索引还是有必要的。