MySQL中count(字段),count(主键 id),count(1)和count(*)的区别

说白了,InnoDB中count()的性能排名最快,其次是count(主键id),然后是count(1 ),最后是count(nullable field)。
这背后其实隐藏着价值转移和零判断的物理差异。

先说最重要的一点:count()知道结果集肯定不为空,所以直接扫描全表,但不取值。
服务器层直接按行累加1 去年我们跑的电商订单报表项目中,使用count()比count(id)快了足足3 秒,而且执行计划中的额外字段中没有像“选择行”这样的耗时操作。
还有一点就是,即使count(主键id)也要扫描全表,引擎也会解析数据行,直接获取ID值。
到了这个阶段,空值的可能性就被消除了。
我们测试了3 000级的数据表,这比count()慢了大约1 5 %。
还有另一个重要的细节:count(1 ) 比 count(id) 更快,因为 1 是一个常量。
引擎可以避免解析额外的数据,直接使用系统位来计数,这样可以在运行点时节省大量的CPU解析时间。

一开始我以为count(id)和count(主键id)的性能还不错,后来发现不对。
主键ID涉及字段解析,1 是纯数字常量。
许多人没有注意到这一点。
等等,还有一件事。
对于可为空的字段,每次执行扫描时都必须执行额外的空评估。
去年我测试了一个计数操作,其中表中某个字段的空值超过 5 0%,速度慢了一倍。
说实话,这很令人沮丧。

建议直接使用count()进行聚合统计,除非你知道某个特定的非主键字段的空率极低,并且有严格的性能要求。
你怎么认为?

MYSQL COUNT(*) 和 COUNT(1)你真的会用吗?

上周,一位客户问我,他们公司在使用MySQL数据库时,经常会看到COUNT()和COUNT(1 )这两个函数,想知道它们之间有什么区别,哪个更好用。
我告诉他,其实在MySQL 8 .0版本及以后的版本中,这两个函数在性能上是没有区别的。

COUNT()表示对表中的所有行进行计数,无论这些行的列值是否为NULL。
在InnoDB等事务性存储引擎中,由于可能存在并发事务,行数可能会发生变化,因此COUNT()统计的是当前事务可见的行数。

对于COUNT(1 ),在过去的一些MySQL版本中,有些人认为它比COUNT()更高效,但那已经成为过去了。
在MySQL 8 .0及更高版本中,COUNT(1 )中的1 实际上是一个常量表达式,对COUNT函数的行为没有影响。

官方文档还称,从MySQL 8 .0.1 3 版本开始,针对InnoDB引擎的单线程工作负载,对COUNT()的查询性能进行了优化。
当InnoDB执行COUNT()时,它会遍历最小的可用辅助索引。
如果没有辅助索引,就会扫描聚集索引。

如果您只是想快速获取大概的行数,还可以使用 SHOW TABLE STATUS 命令获取表的元数据,其中包含行数的估计值。

所以,作为开发者,我的建议是多看官方文档,自己实践一下。
在大多数情况下,使用 COUNT() 更加直观和简洁,因为它直接意味着“计算所有行”。
反正就看你自己了,不过我个人觉得性能上没有太大区别,就用哪个更方便吧。
这个问题我还在思考,毕竟每个项目的情况可能不一样。