【以下内容总结自丁奇老师的MySQL45讲】
MyISAM引擎直接记录了表的行数,所以会很快。
但是InnoDB不同。不存在这个字段,InnoDB 是索引组织表,主键索引树的叶子节点是数据,而普通索引树的叶子
节点是主键值。所以,普通索引树比主键索引树小很多。对于 count() 这样的操作,遍历哪个索引树得到的结果逻辑上都是一样的。因此,MySQL 优化器会找到最小的那棵树来遍历。在保证逻辑正确的前提下,尽量减少扫描的数据量,是数据库系统设计的通用法则之一。
这里,首先你要弄清楚 count() 的语义。count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL,累计值就加 1,否则不加。最后返回
累计值。
所以,count(
)、count(主键 id) 和 count(1) 都表示返回满足条件的结果集的总行数;而
count(字段),则表示返回满足条件的数据行里面,参数“字段”不为 NULL 的总个数。
至于分析性能差别的时候,你可以记住这么几个原则:

  1. server 层要什么就给什么;
  2. InnoDB 只给必要的值;
  3. 现在的优化器只优化了 count(*) 的语义为“取行数”,其他“显而易见”的优化并没
    有做。
    这是什么意思呢?接下来,我们就一个个地来看看。
    对于 count(主键 id) 来说,InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来,返
    回给 server 层。server 层拿到 id 后,判断是不可能为空的,就按行累加。
    对于 count(1) 来说,InnoDB 引擎遍历整张表,但不取值。server 层对于返回的每一
    行,放一个数字“1”进去,判断是不可能为空的,按行累加。
    单看这两个用法的差别的话,你能对比出来,count(1) 执行得要比 count(主键 id) 快。因
    为从引擎返回 id 会涉及到解析数据行,以及拷贝字段值的操作。
    对于 count(字段) 来说:
    加微信 ixuexi66 获取最新一手资源
  4. 如果这个“字段”是定义为 not null 的话,一行行地从记录里面读出这个字段,判断不
    能为 null,按行累加;
  5. 如果这个“字段”定义允许为 null,那么执行的时候,判断到有可能是 null,还要把值
    取出来再判断一下,不是 null 才累加。
    也就是前面的第一条原则,server 层要什么字段,InnoDB 就返回什么字段。
    但是 count() 是例外,并不会把全部字段取出来,而是专门做了优化,不取值。
    count(
    ) 肯定不是 null,按行累加。
    看到这里,你一定会说,优化器就不能自己判断一下吗,主键 id 肯定非空啊,为什么不能
    按照 count() 来处理,多么简单的优化啊。
    当然,MySQL 专门针对这个语句进行优化,也不是不可以。但是这种需要专门优化的情
    况太多了,而且 MySQL 已经优化过 count(
    ) 了,你直接使用这种用法就可以了。
    所以结论是:按照效率排序的话,*count(字段))*,所
    以我建议你,尽量使用 count(
    )。