当前位置: 首页 > 科技观察

你总是认为count(1)比count(-)更有效率吗?

时间:2023-03-14 09:34:36 科技观察

MySQLcount(1)真的比count(*)快?反正同事都这么说,我觉得也对,我自己就没研究过?如果我告诉你它们是一样的,你相信吗?什么?带Where条件的计数会根据扫描结果统计所有行,其性能更多取决于你的Where条件,所以本文只说明不带Where的情况。MyISAM引擎会记录一张表的总行数,所以在执行count(*)时,会直接返回数字,执行效率很高。MySQL5.5之后,默认引擎切换为InnoDB。因为加入了版本控制(MVCC),InnoDB有多个事务同时访问数据和更新操作。每笔交易都需要保持自己的可见性。那么每个事务查询的行数也不一样,所以无法缓存具体的行数,需要每次统计所有的行数。那么count(1)和count(*)有什么区别吗?InnoDB以相同的方式处理SELECTCOUNT(*)和SELECTCOUNT(1)操作。没有性能差异。这是官网上的解释,直接点击阅读原文查看官方文档,所以这两个实现其实是一样的,为什么会一样呢?要探究这个问题,我们首先需要了解计数的含义。下面是官网给出的定义:返回一个SELECT语句检索到的行中expr的非NULL值个数的计数。结果是一个BIGINT值。通俗解释就是返回SELECT语句检索到的行中expr的非NULL值的个数。这里我们理解首先是一个聚合函数,然后SELECT结果集才算,但是要求参数不为NULL。然后我们继续看官网的内容:COUNT(*)有点不同,它返回的是检索到的行数的计数,不管它们是否包含NULL值。大致内容就是count(*)不同,他不关心返回值是否为空,你会计算它的count,因为count(1)中的1是常量表达式,那么count(*)或count(1)统计了所有的结果集,所以本质上是没有区别的。当然InnoDB本身在这个地方也做了一些优化,会使用最小二级索引来优化count查询。如果没有二级索引,则选择聚簇索引。这样的设计从IO的角度来说节省了很多开销。这里我们理解count(*)和count(1)本质上是一样的,那么count(column)呢?count(column)也会遍历整个表,但不同的是,它会在得到列的值后,判断是否为空,然后累加。如果需要为主键解析内容,如果是次要的,需要根据主键重新获取内容。又是一个IO操作,所以count(column)的性能是一定的不如前两者,如果按照效率来比较:count(*)=count(1)>count(primarykey)>count(column)既然count(*)在query中依赖于所有的数据集,是不是我们在设计的时候,也需要尽可能的避免fullcount?通常,我们会对可预见的计数查询做一个适当的缓存,可以是Redis,也可以是独立的MySQL计数表。当然,无论哪种方式,我们都需要考虑一致性问题。文章到此结束。是不是对count()有了新的认识?文中提到了一些关键词:聚簇索引、InnoDB、MyISAM、MVCC不是本文的重点。感兴趣的可以继续关注订阅号或者置顶。这些关键字后面会一一解释。