剖析 mysql count
mysql count 执行过程与分析
全篇都是以 InnoDB 为前提
1 | select count(*) from t; |
在保证逻辑正确的情况下,尽可能的扫描少的数据
看一下搜索引擎做了那些优化
- 索引优化
- 主键索引上是有数据的,而普通索引叶子节点数据是主键值,所以普通索引比主键索引小
- mysql 优化器就会选择数据量最小的普通索引树来遍历
不同 count 的用法
用法:
count(字段)
count(主键 id)
count(*)
count(1)
count(字段)
- 如果这个
字段
定义为not null
的话,一行一行的数据读出这个字段
, 判断不为null
的进行累加。 - 如果这个
字段
定义允许为null
的话, 执行的时候判断有可能是null
的, 把值取出来判断一下,不为 null 的才累加。
原则: server 层要什么字段,InnoDB 就返回什么字段。
count(主键id)
- InnoDB 引擎会遍历整张表,把每一行的 ID 值取出来,返回给 server 层
- server 层拿到数据不为空的,就按行累加
count(1)
- InnoDB 引擎会遍历整张表,但不取值。
- server 层对于取出来的每一行,放一个数字
1
进去, 判断不可能为空的,按行累加
但看 count(主键id)
和 count(1)
的用法差别的话,能对比出来, count(1) 性能比 count(主键 id) 效率要高,因为引擎返回 id 会涉及解析数据行,以及拷贝字段值的操作。
count(*)
- 并不会把全字段取出来,而是做了单独的优化。
count(*)
肯定不为 null ,按行累加。
看到这里肯定有疑问,优化器不会判断一下吗, 主键 id 肯定不为空,直接转换成 count(*)
不就好了,多简单的优化。
当然 mysql 针对这个语句优化也不是不可以,但是需要专门优化的情况太多,而且 mysql 已经优化过了count(*)
, 你可以直接用count(*)
。
结论:
按照效率由低到高: count(字段)
< count(主键id)
< count(1)
~= count(*)