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+树的数据量。计算表格长度、数据总量时,推荐直接用这个。













Comments | NOTHING