count(*)优化

目录

序言

对比

5.7.26

5.7.16

5.6.47 

总结


序言

一谈到mysql优化,肯定有很多人会提到count(*)优化,百度到的面试题和各种博客,一查一大堆。count(*),真的需要优化吗,如果需要优化那该怎么优化,本文将会从mysql5.6.46,、5.7.16、5.7.26三个版本分别讨论。讨论的前提是innodb搜素引擎。

对比

5.7.26

运行环境

联想拯救者Y7000

表结构

数据量 

1006950

只有主键索引时 

EXPLAIN select count(*) from employees;---->0.581 0.657 0.572 0.689 0.638

EXPLAIN select count(0) from employees;---> 0.600 0.669 0.531 0.739 0.587

EXPLAIN select count(id) from employees;--->0.651 0.670 0.612 0.636 0.553

以上三条执行结果都是下图

EXPLAIN select count(name) from employees;--->0.717 0.681 0.668 0.715 0.714

前三条的执行计划是一样的,速度也都是相差不大,都使用到了主键索引。

而第四条没有使用到索引,虽然扫描行数和前三条一样,由于需要进行NULL值判断,所以速度稍微慢了点

得出结论:从执行计划和执行速度上看要count(*) count(0) count(id)使用任何一个都可以。而count(普通列)速度可能会稍微慢了点但是不太影响,主要它结果不计null值,所以根据需求使用

使用普通索引

create index idx_name on employees(name)

EXPLAIN select count(*) from employees;---->0.549 0.525 0.506 0.550 0.524 0.498

EXPLAIN select count(0) from employees;--->  0.605 0.438

EXPLAIN select count(id) from employees;--->。。。

EXPLAIN select count(name) from employees;--->。。。

同样以上四条条执行结果都是下图

为什么前三条都走了普通索引,即使第三条都指定主键id。这就需要了解innodb的数据和索引保存结构了。简单的来说主键索引树保存了主键和其它所有数据,而普通索引树保存了该索引列和对应的主键,首先从树大小来看,普通索引树更小搜索更快,所以mysql底层优先走了普通索引。

第四条虽然执行计划也是和上三条一样,但是它指定了列,并且它是可以为null的,所以它在计算的时候不把null值计算在内,需要进行判断是否null值处理。而上三条只需计数不需取值判断是否为null

5.7.16

运行环境

联想天逸510Pro

表结构

同上

数据量 

548626

只有主键索引时 
EXPLAIN select count(*) from employees;---->0.639 0.652 0.866 0.729 0.605 0.705

EXPLAIN select count(0) from employees;--->0.652 0.620 0.632 0.633 0.645 0.711

EXPLAIN select count(id) from employees;--->0.621 0.648 0.612 0.628 0.681 0.643

以上三条执行结果都是下图

EXPLAIN select count(name) from employees;--->0.678 0.639 0.611 0.641 0.631 0.635

这个版本的mysql前三条语句竟然都没有使用到索引,而使用了Select tables optimized away,优化器认为可以在优化阶段读取要读取的行(例如,通过读取索引行)时,不需要在查询执行期间读取任何表。意思是在优化阶段就可以获取到所需要的值,已经是很优的sql了。但和第四条语句速度相差可以忽略不计(这个结果仅供参考)

使用普通索引

create index idx_name on employees(name)

前三条同上

EXPLAIN select count(name) from employees;--->0.239 0.171 0.136 0.128 0.145

我靠,可怕吗,第三个走了idx_name索引竟然快了这么多。

可说明 5.7.16到5.7.26已经多count又做了一次优化

5.6.47 

执行计划和5.7.26一模一样

总结

(1)count(*) count(0) count(主键)底层执行计划是一样的,而且mysql优化器会将其优化成count(0) (trace后可见),所以说count(*)没有必要进行优化。
(2)如果需要全表count(*)而且表比较大的话,最好表中有辅助索引(非主键索引)
(3)如果需要范围count(*),请给范围查找的字段加合适的索引,否则会进行全表扫描 where语句优化和其它类型的优化都需要注意哦
(4)count(*) count(0) count(主键)会计入NULL,count(可为null的列)不会计入NULL。所以除非需要只计算固定列为不为NULL的数据时,才使用count(列)
(5)请放心大胆的使用count(*)吧,注意(2)(3)(4)条就可以喽

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值