MySQL-count(1)、count(*)与count(列名)的执行区别
https://time.geekbang.org/column/article/72775
MyISAM引擎
因为该引擎没有事务和MVCC,因此会保存一个行数的变量,当在执行无where条件的行数统计时,就会直接返回该行数变量。
当然如果有where条件,还是要逐行扫描判断,得到满足条件的行数。
innodb引擎
因为innodb的MVCC机制,导致不同事务在同一时刻看到的数据都是不一样的,因此统计到的行数也是不一样的。所以没办法保存一个行数的变量,必须每次去实时的扫描统计。但是不同的count语句的统计逻辑和优化也不一样。
count(*)
该语句会选择一个空间最小的索引进行扫描,最后给server层返回一个行数
count(id)
该语句会扫描主键索引,每扫描一行就给server层返回该行id,server层每得到一个id就将当前行数加1,最后得到了一个总的行数
count(1)
该语句会扫描主键索引,每扫描一行就给server层返回1,server层将这些1不断相加,最后得到了一个总的行数
count(字段)
该语句扫描该字段,每扫描一行就会该字段值,server层收到该数据之后会判断是否为空,不为空才会将当前行数加1,最后得到一个总的行数。
可知该语句只能得到该字段不为空的总行数,也可以跟count(*)返回行数相减得到该字段为空的行数
show table status
索引统计的值是通过采样来估算的。实际上,TABLE_ROWS 就是从这个采样估算得来的,因此它也很不准。有多不准呢,官方文档说误差可能达到 40% 到 50%。所以,show table status 命令显示的行数也不能直接使用。
所以结论是:按照效率排序的话,count(字段)<count(主键 id)<count(1)≈count(*),所以我建议你,尽量使用 count(*)。