阿里巴巴JAVA开发手册中提到:
1. 【强制】不要使用 count(列名)或 count(常量)来替代 count(*),count(*)是 SQL92 定义的标
准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。
说明:count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行
原因:
1、COUNT(expr) ,返回SELECT语句检索的行中expr的值不为NULL的数量。结果是一个BIGINT值。
2、如果查询结果没有命中任何记录,则返回0。
关于count(常量)和count(*)可以理解为常量和*一定不为null,所以查询到的就是所有的行数。而count(列名)则需要判断列的值不为null的行数。除了查询得到结果集有区别之外,count(*)是SQL92的标准统计行数语法,所以MySQL会对他进行优化。在常见的两个数据库引擎中,MyISAM是单独对行数进行一个存储的,在不使用where的前提下,使用count(*)可以直接返回行数。由于MyISAM不支持事务,锁是表级锁,所以这个数据是可靠的。但是在InnoDB中,并发的事务让存储表行数的方法变得很不可靠。所以InnoDB中对count(*)y优化的方法就是使用索引。
InnoDB中索引分为聚集索引和非聚集索引,聚集索引的叶子节点存储的是整行的数据,而非聚集索引的叶子节点存储的是该行记录主键的值,相比之下非聚集索引比聚集索引小,所以InnoDB会优先的使用非聚集索引进行扫表。这个可以使用Explain进行验证。
现在很明显的是count(*)和count(常量),会比count(列名)少了判空的过程,所以效率更高。关于前两个的比较,MySQL官方给出的答案是,他们的优化是一样的,效率也会是一样的。但是如上所说,count(*)是标准语法,所以还是使用count(*)。