1、count()函数的执行流程

 count()函数被用来统计一个表中的记录条数,count函数会分析传入的参数,如果传入参数是一个字段,那么由InnoDB扫描取出记录的该字段值出来返回给Server层,Server层判断值为null则不将该记录计入总数,反之则将统计数+1;传入参数是非字段则InnoDB会返回一个空行,Server层直接对该参数进行判空,非null则会将统计数按行累加,null则最终统计结果为0。

 常见的count函数如count(*),在MyISAM引擎中它的执行效率非常高,由于不支持事务,可以认为是一个单线程环境,任何时候表的记录行数都是确定的,因此可以在磁盘中记录每个表的记录数,执行count(*)函数时直接返回该数即可,但在InnoDB中就不能如此了。

2、InnoDB的count函数执行效率

 InnoDB是支持事务的,同一个表可以多个线程并发执行,在MVCC的控制下,每个事务可见的记录条数可能是不一样的,因此无法通过维护一个数来记录表的行数。事务在执行count()函数时必须一条一条地读取记录判断其是否可见,效率比之MySIAM较低。既然必须逐条读取记录统计条数,那么如果要进行优化自然就得从读取的内容入手,如果能够读取更少的数据做更少的操作就获得准确的记录条数,那么对提高效率是有帮助的,而读取什么数据做什么操作,就要看传入的参数是什么了,通常可以分为以下四种情况:

  • count(主键字段):在传入主键字段时,InnoDB会选择扫描表中占用最小索引树的叶子节点,然后从扫描到的记录中提取出主键值给Server层,然后Server层做非空判断,由于主键字段恒不为空,因此最终会得到表中的记录总数;
  • count(1):传入参数为”1″时,同样是扫描主键索引叶子节点,区别就在于”1″不是字段,因此InnoDB扫描到记录后不需要对记录进行解析提取字段,而是直接返回一个空行,而Server层是对1进行判空,1肯定不是null,将统计数+1。由于InnoDB不需要对扫描到的记录进行解析,因此count(1)的效率要比count(主键字段)要高;
  • count(字段):
    • 如果该字段建立了索引,那么InnoDB需要就扫描该字段所在的索引树,然后解析提取该字段的值返回给Server层,如果为null则该记录不计入统计数,不为null则统计数+1,最终得到该字段不为null的记录总数;
    • 如果该字段没有建立索引,那么InnoDB就得扫描主键索引树解析提取出该字段返回给Server层,Server层进行判断计数,规则和上面一样。但由于主键索引是聚簇索引,需要将扫描表中记录的所有字段数据,效率低;
  • count(*):传入的参数为*时,InnoDB会选择表中最小索引树进行扫描,由于*不是字段,不需要进行解析提取字段,所以也是返回空行再由Server层进行判空计数,*恒不为空,最终结果是表中记录的总数

 综合上面的分析,count()函数执行效率总结如下:
  count(字段(无索引)) < count(索引字段) <= count(主键) ≈ < count(1) ≈ count(*)
  由于count(主键)会选择最小索引树,因此如果count(索引字段)中的索引树不是最小的话,那么count(主键)的效率是会高一些的

 而如果想要得到所有记录的数量,那么就必须选择不会为空的参数,即:
  count(非空普通字段)、count(主键字段)、count(*)、count(1)


版权声明:本文为weixin_48460141原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_48460141/article/details/124618767