当前位置: 首页 > 图灵资讯 > java面试题> 金三银四精选java面试题-count(*)与count(1)有什么区别

金三银四精选java面试题-count(*)与count(1)有什么区别

来源:图灵教育
时间:2023-12-19 15:05:18
 

count(*)与count(1)有什么区别

 

工作中,经常需要做统计,比如分页的时候,需要知道表中总共有多少行数据,这时就会用到count(),那到底应该用count(*)呢?还是count(1)呢?还是count(某个字段)呢?

 

MySQL官网中,其实就对count(*)做了描述

 

在官网中是这么描述count(expr)的:

Returns a count of the number of non-NULL values of expr in the rows retrieved by a SELECT statement. The result is a BIGINT value.

If there are no matching rows, COUNT() returns 0

 

翻译一下就是,返回SELECT语句结果中非NULL的统计结果,如果没有匹配的行,则返回0。

 

比如下面这个sql

select count(*) from t1

 

就是统计:

select * from t1

这个sql查询得到的结果的总行数。

 

紧接着,官网就单独描述了一下count(*):

COUNT(*) is somewhat different in that it returns a count of the number of rows retrieved, whether or not they contain NULL values.

 

意思是,count(*)有点不一样,一般的count()不会统计NULL值,但是count(*)会统计到NULL值。

 

比如现在有一个表,只有一个字段,有三条记录,两个f,一个null

 

此时count(*)的结果为3,count(e)的结果为2,count(1)的结果为3

 

在MyISAM中,会有单独的地方记录表的行数,所以在MyISAM中执行count(*)是比较快的,当然前提条件是sql语句中没有where条件,因为MyISAM记录的就是无条件下的表中总共的行数。

 

但是Innodb中没有这种机制,因为Innodb支持事务,事务又有不同的隔离级别,对于同一个表来说,不同的事务可能同时在操作这个表,并且每个事务是独立的,A事务插入了一条数据,B事务可能是不需要知道的,这样就导致Innodb不能像MyISAM那样在某一个地方记录记录总行数了。

 

那么Innodb中的count()是怎么执行的呢?会利用索引。

 

比如在执行count(*)时,会选择表中的某一个索引,因为索引B+树中就记录了表中的所有数据行(每行数据的某些字段),所以利用索引页可以更快的统计出总行数。

 

比如现在有一张表,有a,b,c,d,e五个字段,其中a是主键,b,c,d是一个联合索引,此时如果:

explain select count(*) from t1

 

会发现,这个sql会走bcd联合索引

 

因为bcd联合索引对于的B+树存的字段更少,导致B+树的叶子节点个数更少,但是并没有影响数据行数(没行只存了b,c,d字段,严格来说也存了a字段,但是e字段是肯定没有存的)。

 

这就是count(*),相当于会利用索引来统计总行数。

 

而count(1)和count(*)是一样的,比如官网中就这么描述的:

InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.

 

而如果count(某个字段),那么也看这个字段有没有可用的索引,如果有利用索引统计,如果没有则进行全表扫描统计,当然会过滤掉null值。

 

以上就是我结合官网以及实验的分析过程,总结如下:

  1. MyISAM中count(*)比较快,因为可以直接取到MyISAM帮我们统计的总行数
  2. Innodb中count(*)会选择索引,然后利用索引统计出来总行数
  3. count(1)和count(*)是一样的,不管是Innodb还是MyISAM
  4. count(某个字段)会选择该字段可用的索引进行统计,如果没有则进行全部扫描,只要是count(某个字段)就会过滤掉null值,不管走没走索引