雨翔河
首页
列表
关于
mysql 下 count (*) 和 count (1) 的区别
2019-04-04 07:27
今天看公司项目发现了一个奇怪sql写法 ``` select count(8) from .... ``` 这也许是开发人员不小心或者是习惯把`*`写成了`8`,当然这并不影响程序运行的结果。 由此引发了我想知道`count(*)`和`count(1)`的区别。 其实关于`count(*)`和`count(1)`性能的争论文章特别多,这类文章都没讲到重点。 我觉得我今天说的这个答案算的上是很权威的,因为答案来自mysql官方文档关于count函数的解释。 现在我能找到的mysql最老的版本文档是5.5 链接如下: https://dev.mysql.com/doc/refman/5.5/en/group-by-functions.html 关于 `count(*)`和`count(1)` 有这样一段话: > InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference. 就是说在 InnoDB 引擎下,这两个其实没有性能上的差异。 但是在MyISAM引擎是有差异的,原文是这样说的: > For MyISAM tables, COUNT(*) is optimized to return very quickly if the SELECT retrieves from one table, no other columns are retrieved, and there is no WHERE clause. For example: This optimization only applies to MyISAM tables, because an exact row count is stored for this storage engine and can be accessed very quickly. COUNT(1) is only subject to the same optimization if the first column is defined as NOT NULL. MyISAM引擎对`count(*)`进行了优化,可以快速得到结果. 但是如果使用`count(1)`,那么如果当第一列的结果不为空的时候才有这种优化,所以在MyISAM引擎下 如果第一列为空的话`count(1)`的查询效率是没有`count(*)`高的。 接下来对mysql官方的文档大致翻译下: `COUNT(*)`返回检索到的行数的计数,不管它们是否包含空值。 对于InnoDB这样的事务性存储引擎,存储准确的行数是不太现实的,因为多个事务可能同时发生,每个事务都有可能影响计数。 InnoDB不保留表中的行数,因为并发事务可能同时“看到”不同的行数。因此,`SELECT COUNT(*)`语句只计算当前事务可见的行。 为了处理`SELECT COUNT(*)`语句,InnoDB扫描表的索引,如果索引不是完全在缓冲池中,那么这将花费一些时间。为了更快地计数,创建一个计数器表,并让应用程序根据它的插入和删除来更新它。但是,当数千个并发事务同时启动对同一个计数器表更新时,这种方法可能无法很好地维护。如果想要一个大致的结果,则使用SHOW TABLE STATUS。 InnoDB以同样的方式处理`SELECT COUNT(*)`和`SELECT COUNT(1)`操作。没有性能差异。 对于MyISAM表,如果使用SELECT从一个表中检索,没有检索其他列,也没有WHERE子句,那么`COUNT(*)`被优化为快速返回。例如: ``` mysql> SELECT COUNT(*) FROM student; ``` 这种优化只适用于MyISAM表,因为为这个存储引擎存储了准确的行数,并且可以非常快速地访问。`COUNT(1)`只有在第一列被定义为NOT NULL时才进行相同的优化。 ## 总结: 很明显在进行统计的时候最好就是使用`count(*)`,至少在5.5+的版本可以这样做,不管是在InnoDB还是MyISAM都能达到最佳性能。 目前mysql官方最新的文档版本是8.0,链接为: https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_count 这里我要插下嘴,在8.0版本的mysql,对于 `count(*)` 是做了额外的优化的, 优化内容大致是: > 从MySQL 8.0.13开始,如果没有额外的子句(如WHERE或GROUP BY),那么InnoDB表的tbl_name查询性能中的SELECT COUNT(\*)将针对单线程工作负载进行优化。除非索引或优化器提示指示优化器使用不同的索引,否则InnoDB进程通过遍历最小的可用辅助索引来选择COUNT(\*)语句。如果不存在二级索引,InnoDB将通过扫描聚集索引来选择COUNT(\*)语句。
类型:工作
标签:mysql,count
Copyright © 雨翔河
我与我周旋久
独孤影
开源实验室