count(1)、count(*) 与 count(列) 的区别?
一、那种count的性能最好呢?
先说结论:count(*) = count(1) > count(索引列) > count(字段)
count()是神魔? count()是一个聚合函数,找出符合记录中字段不为NULL的数量。 例如:count(主键),server层会维护一个count变量,向引擎发出请求,如果只有主键索引,innodb引擎会便利聚簇索引将所有主键值返回给server,server会做判断,如果不为NULL,边将count值+1。但是如果有二级非聚簇索引,引擎便会编辑二级索引的叶节点,因为一般二级索引数据较少,存储空间小,遍历效率更高。
二、执行过程
- count(1):引擎将读取的记录返回给server,因为没有指定具体的字段,所以不会作是否为NULL判断,计算的是所有的记录值。同理,如果有二级索引会遍历二级索引。相对于count(主键字段)不需要读取具体的值,所以效率更高。
- count(*):mySQL会转换为count(0),所以执行的效率和count(1)一样。
在 MySQL 5.7 的官方手册中有这么一句话: InnoDB handles SELECT COUNT() and SELECT COUNT(1) operations in the same way. There is no performance difference. 翻译:InnoDB以相同的方式处理SELECT COUNT()和SELECT COUNT(1)操作,没有性能差异。
- count(字段):会走全表扫描,但是如果二级索引有此字段,便会走二级索引。
三、为什么要走全表索引?
使用MyISAM引擎时,count()时间复杂度是O(1),因为MyISAM表中会存储row_count值记录,由于MyISAM由表级锁保证一致性。 但是InnoDB支持MVCC,所以会同时存在多个事务同时操作表,无法同时维护row_count 变量。但是如果加上where条件,则两个引擎都使用的是全表扫描。
四、如何优化count()
- 近似值:可以使用explain来获取大概的行数;
- 可以建立单独的表记录相应的行数;
下一篇:
MySQL进阶实战5,为什么查询速度会慢