本文正在参加「技术专题19期 漫谈数据库技术」活动

前言

大家好,我是小郭,MySQL关于Count你知道多少

计算数据的需求在咱们日常开发中是十分容易遇到了,MySQL也支持多种的核算的函数,

接下来咱们来看一看他们之间有什么差异,以及他们是否存在一些坑。

count(*)、count(1)、count(id)的差异

count的意义:count() 是一个聚合函数,关于回来的成果集,一行行地判别,假如 count 函数的参数不是 NULL,累计值就加 1,否则不加。最后回来累计值。

count(字段)比较特别,则表明回来满意条件的数据行里边,参数“字段”不为 NULL 的总个数

剖析功能不同原则

  1. server 层要什么就给什么;
  2. InnoDB 只给必要的值;
  3. 现在的优化器只优化了 count(*) 的语义为“取行数”,其他“显而易见”的优化并没有做

例子:

count(主键 id) 来说,InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来,回来给 server 层。server 层拿到 id 后,判别是不行能为空的,就按行累加。

count(1) 来说,InnoDB 引擎遍历整张表,但不取值。server 层关于回来的每一行,放一个数字“1”进去,判别是不行能为空的,按行累加。

count(字段),server要字段,就回来字段,假如字段为空,就不做计算,字段的值过大,都会形成效率低下。

效率排序

count(字段)<count(主键 id)<count(1)≈count(*)

为什么count(*)最快?

优化器做了工作,找到最小的数来遍历。

InnoDB 是索引组织表,主键索引树的叶子节点是数据,而一般索引树的叶子节点是主键值。所以,一般索引树比主键索引树小很多。关于 count(*) 这样的操作,遍历哪个索引树得到的成果逻辑上都是相同的。因此,MySQL 优化器会找到最小的那棵树来遍历。在确保逻辑正确的前提下,尽量减少扫描的数据量,是数据库系统设计的通用规律之一。

关于NULL的几个坑

// 数据中存在null值数据
select count(*) from audit_log a;
成果:1
select count(id) from audit_log a;
成果:0

咱们看到count的成果不一致,记录数应该是1,count(id)却等于0

这是由于count(字段)是不计算,字段值为null的值

所以在字段为非空字段的情况下,需求使用count(*)来处理这个问题。

count(*)小结

  1. MyISAM 表虽然 count(*) 很快,可是不支持业务;
  2. show table status 指令虽然回来很快,可是不精确;
  3. InnoDB 表直接 count(*) 会遍历全表,虽然成果精确,但会导致功能问题。