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