关注「Java视界」公众号,获取更多技术干货

count(*) 和 count(列名)的区别

count 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL,累计值就加 1,否则不加。最后返回累计值。

count(*)是SQL92定义的标准统计行数的语法,跟数据库无关,跟NULL和非NULL无关。

count(*)会统计值为NULL的行,而count(列名)不会统计此列为NULL值的行。

idname
1张三
2李四
3NULL

这里count(*)就是 3, count(`name`)就是 2。

最好不要使用count(列名)或count(常量)来替代count(*),除非统计的都是非空的记录总数。

四种 count 的区别:

既然都说到这里了,干脆就把 4 种 count 的区别都对比下:

  • count (字段):遍历整张表,需要取值,判断 字段!= null,按行累加;

  • count (主键) :遍历整张表,需要取 ID,判断 id !=null,按行累加;

  • count (1) :遍历整张表,不取值,返回的每一行放一个数字 1,按行累加;

  • count (*):不会把全部字段取出,专门做了优化,不取值。count ( * ) 肯定不是 null(没有就是0),按行累加。

  • count(*)和count(1) 和count(0)一样,都包括对NULL的统计

count (主键) 可能会选择最小的索引来遍历,而 count (字段) 的话,如果字段上没有索引,就只能选主键索引,所以性能上 count (字段) < count (主键)

因为 count (*) 和 count (1) 不取字段值,减少往 server 层的数据返回,所以比其他 count (字段) 要返回值的性能较好;

1.由于count(*)的算法与列偏移量无关,所以count(*)最快。

2.因为count(指定的有效值),执行计划都会转化为count(*)

3.列的偏移量决定性能,列越靠后,访问的开销越大

如果指定的是列名,会判断是否有null,null不计算

所以结论是:

count(*) = count(1) = count(0) > count(主键 id) > count(字段)

MySQL 对 count (*) 做了什么优化?

InnoDB 是索引组织表,主键索引树的叶子节点是数据,而普通索引树的叶子节点是主键值。因此,普通索引树比主键索引树小很多

对于 count (*) 来说,遍历哪个索引树得到的结果逻辑上都是一样的。MySQL 优化器会找到最小的那棵树来遍历。在保证逻辑正确的前提下,尽量减少扫描的数据量,是数据库系统设计的通用法则之一

count (*) 在不同引擎中的实现方式是不一样的:

  • MyISAM:不支持事务,把一个表的总行数存在了磁盘上,因此执行 count (*) 的时候会直接返回这个数,效率很高;当然这里讨论的是没有 where 条件下的 count,如果有 where 条件,那么即使是 MyISAM 也必须累积计数的。

  • InnoDB:支持事务,它执行 count (*) 的时候,需要把数据一行一行地从引擎里面读出来,然后累积计数。

posted @ 2022-06-25 14:03  沙滩de流沙  阅读(1636)  评论(0编辑  收藏  举报

关注「Java视界」公众号,获取更多技术干货