剖析 mysql count

mysql count 执行过程与分析

全篇都是以 InnoDB 为前提

1
select count(*) from t;

在保证逻辑正确的情况下,尽可能的扫描少的数据
看一下搜索引擎做了那些优化

  1. 索引优化
    • 主键索引上是有数据的,而普通索引叶子节点数据是主键值,所以普通索引比主键索引小
    • mysql 优化器就会选择数据量最小的普通索引树来遍历

不同 count 的用法

用法:

  • count(字段)
  • count(主键 id)
  • count(*)
  • count(1)

count(字段)

  1. 如果这个字段 定义为 not null的话,一行一行的数据读出这个字段, 判断不为 null的进行累加。
  2. 如果这个字段 定义允许为 null的话, 执行的时候判断有可能是 null的, 把值取出来判断一下,不为 null 的才累加。

原则: server 层要什么字段,InnoDB 就返回什么字段。

count(主键id)

  1. InnoDB 引擎会遍历整张表,把每一行的 ID 值取出来,返回给 server 层
  2. server 层拿到数据不为空的,就按行累加

count(1)

  1. InnoDB 引擎会遍历整张表,但不取值。
  2. server 层对于取出来的每一行,放一个数字 1 进去, 判断不可能为空的,按行累加

但看 count(主键id)count(1)的用法差别的话,能对比出来, count(1) 性能比 count(主键 id) 效率要高,因为引擎返回 id 会涉及解析数据行,以及拷贝字段值的操作。

count(*)

  1. 并不会把全字段取出来,而是做了单独的优化。
  2. count(*) 肯定不为 null ,按行累加。

看到这里肯定有疑问,优化器不会判断一下吗, 主键 id 肯定不为空,直接转换成 count(*) 不就好了,多简单的优化。

当然 mysql 针对这个语句优化也不是不可以,但是需要专门优化的情况太多,而且 mysql 已经优化过了count(*), 你可以直接用count(*)

结论:

按照效率由低到高: count(字段) < count(主键id) < count(1) ~= count(*)