问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

深度解析MySQL Count函数的工作原理与优化策略

创作时间:
作者:
@小白创作中心

深度解析MySQL Count函数的工作原理与优化策略

引用
CSDN
1.
https://m.blog.csdn.net/qq_45852626/article/details/145461951

在数据库开发和运维工作中,对数据表的记录进行统计是一个常见的需求。MySQL中的Count函数提供了多种参数选择,如count(*)、count(1)、count(主键字段)和count(字段)等。这些不同的参数在执行效率上存在差异,了解其工作原理和优化方法对于提升数据库性能至关重要。本文将深入解析Count函数的工作机制,并提供实用的优化建议。

前言

当我们需要对数据表进行统计时,通常会使用Count函数。然而,Count函数的参数有很多选择,比如count(1)、count(*)、count(字段),它们的执行效率是否有所不同呢?

结论

按照性能排序:
count(*) = count(1) > count(主键字段) > count(字段)

Count是什么

Count()是一个聚合函数,函数的参数可以是任意表达式,不限于字段名。

该函数的作用是:统计符合查询条件的记录中,函数指定参数不为null的记录有多少个。

假设 Count() 函数的参数是字段名,如下:

select count(name) from t_order

语句是统计「 t_order 表中,name 字段不为 NULL 的记录」有多少个。也就是说,如果某一条记录中的name为null,则不会被统计进去。

假设 Count() 函数的参数是数字 1 这个表达式,如下:

select count(1) from t_order

语句是统计「 t_order 表中,1 这个表达式不为 NULL 的记录」有多少个。1表达式为单纯的数字,它永远不是NULL,所以上面的语句就是统计t_order表中有多少个记录。

Count(主键字段)执行过程是什么样的

在通过Count函数统计多少记录时,MySQL的Server层会统计维护一个名为count的变量。

Server层会循环向InnoDB读取一条记录,如果Count函数指定的参数不为Null,那么就会对count+1,直到符合查询的全部记录读取完,就退出循环。

最后将count变量的值发送给客户端。

InnoDB 是通过 B+ 树来保存记录的,根据索引的类型又分为聚簇索引和二级索引,它们区别在于:聚簇索引的叶子节点存放的是实际数据,而二级索引的叶子节点存放的是主键值,而不是实际数据。

下面举个例子来说:

select count(id) from t_order

如果表里只有主键索引,没有二级索引时,那么,InnoDB 循环遍历聚簇索引,将读取到的记录返回给 server 层,然后读取记录中的 id 值,就会 id 值判断是否为 NULL,如果不为NULL,就将count变量+1。

但是如果表中有二级索引,那么InnoDB 循环遍历的对象就不是聚簇索引,而是二级索引。因为相同数量的二级索引记录比聚簇索引记录占用更少存储空间,所以二级索引树更小,遍历二级索引I/O成本比遍历聚簇索引的I/O成本小,因此优化器优先选择的是二级索引。

Count(1)执行过程是什么样子的

下面这条语句作为例子:

select count(1) from t_order

表里只有主键索引,没有二级索引时:

InnoDB 循环遍历聚簇索引(主键索引),将读取到的记录返回给 server 层,但是不会读取记录中的任何字段的值。因为 Count 函数的参数是 1,不是字段,所以不需要读取记录中的字段值。因此server层每从InnoDB读取到一条记录,就将count变量+1。

Count(1) 相比 Count(主键字段) 少一个步骤,就是不需要读取记录中的字段值,所以Count(1)的执行效率比Count(主键字段)高一点。

但是如果表里有二级索引,遍历对象就是二级索引了。

Count(0)执行过程是怎么样的

和Count(1)一样哦。

Count(字段)执行过程是怎么样的

执行效率相比前面的 Count(1)、 Count(*)、 Count(主键字段) 执行效率是最差。

下面这条语句作为例子:

select count(name) from t_order

对于这个查询,会触发全表扫描,所以它的执行效率是比较差的。

如何优化Count(*)

对一张大表经常用 Count(*) 来做统计,其实是很不好的。下面我这个案例,表 t_order 共有 1200+ 万条记录,我也创建了二级索引,但是执行一次

select count(*) from t_order

要花费将近5秒!

我们下面介绍两种方法key进行优化

近似值处理

业务对于统计个数不需要很精确,比如搜索引擎在搜索关键词的时候,给出的搜索结果条数是一个大概值。

我们就可以使用 show table status 或者 explain 命令来表进行估算。行 explain 命令效率是很高的,因为它并不会真正的去查询,下图中的 rows 字段值就是 explain 命令对表的估算值:

额外表保存计数值

想精确的获取表的记录总数,我们可以将这个计数值保存到单独的一张计数表中。我们在数据表插入一条记录的同时,将计数表中的计数字段 + 1。也就是说,在新增和删除操作时,我们需要额外维护这个计数表。

小结

Count函数执行时,如果表里有二级索引,优化器会优先选择二级索引进行扫描。所以如果要执行Count函数时,进行在数据表上建立二级索引,这样优化器会自动采用key_len最小的二级索引进行扫描。还有尽量不要用Count(字段)来统计个数,效率是最差的,会采用全表扫描,如果非要这样做,建议给字段创建一个二级索引。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号