5.4 COUNT这么慢,怎么办?推荐`count(*)`,已官方优化



COUNT这么慢,怎么办?

一、MySQL count()函数

用途:统计个数。有多少个有效的成员。

1.1 count()函数的执行流程,常用于计算表行数

1.2 通过试验,查看性能差异

以数据表customer为例,查看count()函数的性能差异。

查看该表的主键和索引情况:show index from customer;

以上述三个字段,分别做试验。

1.3 count(非索引字段)

1.试验

目的:需要数据表的行数。

select count(first_name) from customer;
explain select count(first_name) from customer;

possible keys:null。说明走了全表扫描;

2.结果

无法使用索引覆盖,也就是说无法使用普通的辅助索引:

行记录是有格式的,不是明明白白写在那里,而是要解析出来。

1.4 count(索引字段)

1.试验

2.理论

问题:虽然走了索引覆盖,server层依然需要每个字段要判空。

索引,能一下子取出所有的字段last_name

只需要遍历B+树就行,没有任何解析行记录的步骤,因为字段last_name就是组成B+树所用的排序的键。

本质原因:辅助索引可以为空的。

疑问:如果是主键,或非空的辅助索引,是不是,server层就不需要每个字段要判空呢?不。还是要判空。

1.5 count(1)

1.试验

MySQL的server层,自己选择了一个索引:

2.理论

1.6 count(*)

表面上看,应该是最慢的。即把所有字段都拿出来,再由server层去判断。

但是,MySQL却对此进行了专门的官方优化:

因为并行事务,会插入、删除数据,导致行数不准;

所以InnoDB不会记录数据表的行数,而是直接从当前B+树中找到数据个数。这样不再去server层一个一个的判空了。

二、小结

2.1 四种用法的效率是不同的

  • 无法使用索引覆盖;必须解析每一行的行记录,把count里的字段给解析出来,开销大。
  • 可以使用辅助索引做索引覆盖,但是依然要取出每个数据送到sever层判空;
  • 不需要取出每个数据,送给server层的数据均是1,但依然要判空;
  • 不需要送数据到server层判空,而是直接遍历B+树,返回B+树的数据量。计算表格长度、数据总量时,推荐直接用这个。

声明:Jerry's Blog|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 5.4 COUNT这么慢,怎么办?推荐`count(*)`,已官方优化


Stop chasing money, and start chasing the solutions to the problem.