偶尔会有这样的需求,查找一个表的行数

    其实在不同的MySQL引擎中,count(*) 有不同的实现方式。

    • MyISAM 引擎把一个表的总行数存在了磁盘上,执行 count(*) 的时候会直接返回这个数,效率很高;
    • InnoDB 引擎,它执行 count(*) 的时候,需要把数据一行一行地从引擎里面读出来,然后累积计数。

    但是如果加过滤条件where的话,MyISAM 引擎也会慢一点

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

    其中count(1),count(主键id),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(*) 肯定不是 null,按行累加。

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