MySQL计数器:count(*)的底层原理与性能真相
14.1 count(*) 的实现方式
-
InnoDB 把数据一行一行地读出来,依次判断自己是否对这个会话可见,可见的行才能够用于计算 “基于这个查询” 的表的总行数。
InnoDB 引擎,可重复读是它默认的隔离级别
MVCC(多版本并发控制),每一行记录都要判断自己是否对这个会话可见。
-
MySQL 优化器会找到最小的那棵树来遍历。在保证逻辑正确的前提下,尽量减少扫描的数据量。
InnoDB 是索引组织表,主键索引树的叶子节点是数据,而普通索引树的叶子节点是主键值。
-
show table status命令的 TABLE_ROWS 显示的行数很不准。官方文档说误差可能达到 40% 到 50%。
14.2 不同的 count
1. count(主键)
- InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来,返回给 server 层。server 层拿到 id 后,判断是不可能为空的,就按行累加。
2. count(1)
- InnoDB 引擎会遍历整张表,但不取值。server 层对于返回的每一行,放一个数字“1”进去,并按行累加。
3. count(字段)
- 如果这个 “字段” 是定义为
not null的话,一行行地从记录里面读出这个字段,判断不是 null,按行累加; - 如果这个 “字段” 定义允许为
null,在执行的时候,还是要把值取出来,再判断一下不是 null,再累加。
4. count(*)
-
MySQL 对
count(*)有优化,认为是取行数,所以,只遍历,不取值。其次,count(*)肯定不会是 null,就直接按行累加。
5. 小结
-
按照效率排序的话,
count(字段) < count(主键 id) < count(1) ≈ count(*)count(*)和count(1)不取字段值,减少往 server层的数据返回,所以,比其他
count(字段)要返回值的【性能】较好; -
所以,我建议你,尽量使用
count(*)。惊不惊喜?意不意外?