MySQL计数器:count(*)的底层原理与性能真相

70 阅读2分钟

MySQL计数器:count(*)的底层原理与性能真相

14.1 count(*) 的实现方式

  1. InnoDB 把数据一行一行地读出来,依次判断自己是否对这个会话可见,可见的行才能够用于计算 “基于这个查询” 的表的总行数。

    InnoDB 引擎,可重复读是它默认的隔离级别

    MVCC(多版本并发控制),每一行记录都要判断自己是否对这个会话可见。

  2. MySQL 优化器会找到最小的那棵树来遍历。在保证逻辑正确的前提下,尽量减少扫描的数据量

    InnoDB 是索引组织表,主键索引树的叶子节点是数据,而普通索引树的叶子节点是主键值。

  3. show table status 命令的 TABLE_ROWS 显示的行数很不准。

    官方文档说误差可能达到 40% 到 50%。

14.2 不同的 count

1. count(主键)
  • InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来,返回给 server 层。server 层拿到 id 后,判断是不可能为空的,就按行累加。
2. count(1)
  • InnoDB 引擎会遍历整张表,但不取值。server 层对于返回的每一行,放一个数字“1”进去,并按行累加。
3. count(字段)
  1. 如果这个 “字段” 是定义为 not null 的话,一行行地从记录里面读出这个字段,判断不是 null,按行累加;
  2. 如果这个 “字段” 定义允许为 null,在执行的时候,还是要把值取出来,再判断一下不是 null,再累加。
4. count(*)
  • MySQL 对 count(*)有优化,认为是取行数,所以,只遍历,不取值。其次,count(*) 肯定不会是 null,就直接按行累加。

5. 小结
  • 按照效率排序的话,count(字段) < count(主键 id) < count(1) ≈ count(*)

    count(*)count(1) 不取字段值,减少往 server层的数据返回,

    所以,比其他 count(字段) 要返回值的【性能】较好;

  • 所以,我建议你,尽量使用 count(*)

    惊不惊喜?意不意外?