1 select count(1) from user;
这个查询来说,InnoDB 引擎会去找到一个最小的索引树去遍历(不一定是主键索引),但是不会读取数据,而是读到一个叶子节点,就返回 1,最后将结果累加。
2 select count(id) from user;
这个查询来说,InnoDB 引擎会遍历整个主键索引,然后读取 id 并返回,不过因为 id 是主键,就在 B+ 树的叶子节点上,所以这个过程不会涉及到随机 IO(并不需要回表等操作去数据页拿数据),性能也是 OK 的。
3 select count(username) from user;
这个查询来说,InnoDB 引擎会遍历整张表做全表扫描,读取每一行的 username 字段并返回,如果 username 在定义时候设置了 not null,那么直接统计 username 的个数;如果 username 在定义的时候没有设置 not null,那么就先判断一下 username 是否为空,然后再统计。
4 select count(*) from user
这个 SQL 的特殊之处在于它被 MySQL 优化过,当 MySQL 看到 count() 就知道你是想统计总记录数,就会去找到一个最小的索引树去遍历,然后统计记录数。
因为主键索引(聚集索引)的叶子节点是数据,而普通索引的叶子节点则是主键值,所以普通索引的索引树要小一些。然而在上文的案例中,我们只有主键索引,所以最终使用的就是主键索引。
现在,如果我修改上面的表,为 username 字段也添加索引,然后我们再来看 explain select count() from user; 的执行计划:
可以看到,此时使用的索引就是 username 索引了,和我们前面的分析结果是一致的。
5 总结
1第一个查询性能最高,
2第二个次之(因为需要读取 id 并返回)
3第三个最差(因为需要全表扫描
4第四个的查询性能则接近第一个。
