banner
NEWS LETTER

关于MySQL的count用法

Scroll down

关于 MySQL 的 count() 用法

count()函数概述

count() 是一个聚合函数,返回指定匹配条件的行数。开发中常用来统计表中的数据。

count(*) 的实现方式

  • MyISAM 引擎把一个表的总行数存在磁盘上,因此执行 count(*) 会直接返回这个数,效率很高。但是在加上 where 限定语句后 MySQL 需要对全表进行检索从而得出 count 的总数。

  • InnoDB 引擎执行 count(*) 时,需要把数据一行一行地从引擎里面读出来,然后累积计数。

为什么 InnoDB 不可以和 MyISAM 一样,把数字也存起来?

  • 因为 InnoDB 即使在同一个时刻的多个查询,由于多版本兵法控制(MVCC)的原因,InnoDB 表返回行数也是不确定的。

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

show table status命令输出结果有TABLE_ROWS用于显示这个表当前有多少行,但不可代替 count(*),因为索引统计的值是通过采样来估算的(MySQL会索引选择错误导致)。

小结

  • MyISAM 表虽然 count(*) 很快,但是不支持事务;

  • show table status命令虽然返回很快,但是不准确;

  • InnoDB 表直接 count(*) 会遍历全表,虽然结果准确,但会导致性能的问题。

不同的 count 用法

count(主键id)

InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来返回给 server 层。server 层拿到 id 后,判断不可能为空的就按行累加。

count(1)

InnoDB 引擎遍历整张表,但不取值。server 层对于返回的每一行,放一个数字“1”进去,判断是不可能为空的,按行累加。

count(1) 执行速度比 count(主键id) 快,因为从引擎返回 id 会涉及到解析数据行,以及拷贝字段值的操作。

count(字段)

  1. 如果字段是 not null 的话,一行行地从记录里面读出这个字段,判断不能为 null,按行累加;

  2. 如果这个字段允许为 null,那么执行的时候,还要取值判断是否为 null,不为 null 才累加。

count(*)

count() 是例外,不会把全部字段取出来,专门做了优化,不取值。count() 肯定不是 null,按行累加。

各个 count 用法的执行速度

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

建议使用 count(*)

其他文章
目录导航
  1. 1. 关于 MySQL 的 count() 用法
    1. 1.1. count()函数概述
    2. 1.2. count(*) 的实现方式
      1. 1.2.1. 为什么 InnoDB 不可以和 MyISAM 一样,把数字也存起来?
      2. 1.2.2. 小结
    3. 1.3. 不同的 count 用法
      1. 1.3.1. count(主键id)
      2. 1.3.2. count(1)
      3. 1.3.3. count(字段)
      4. 1.3.4. count(*)
    4. 1.4. 各个 count 用法的执行速度
请输入关键词进行搜索