count(0)、count(1)和count(*)、count(列名) 的区别

当我们对一张数据表中的记录进行统计的时候,习惯都会使用 count 函数来统计,但是 count 函数传入的参数有很多种,比如 count(1)、count(*)、count(字段) 等。

到底哪种效率是最好的呢?是不是 count(*) 效率最差?图片

一. 哪种 count 性能最好?

哪种 count 性能最好?

我先直接说结论:

图片

要弄明白这个,我们得要深入 count 的原理,以下内容基于常用的 innodb 存储引擎来说明。

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+ 树来保存记录的,根据索引的存储方式又分为聚簇索引和二级索引(即聚簇索引和非聚簇索引。聚簇索引通常与表的主键相关联),它们区别在于,聚簇索引的叶子节点存放的是实际数据,而二级索引的叶子节点存放的是主键值,而不是实际数据。

用下面这条语句作为例子:

//id 为主键值
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,不是字段,所以不需要读取记录中的字段值。参数 1 很明显并不是 NULL,因此 server 层每从 InnoDB 读取到一条记录,就将 count 变量加 1。

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

但是,如果表里有二级索引时,InnoDB 循环遍历的对象就二级索引了。
图片

count(*) 执行过程是怎样的?

看到 * 这个字符的时候,是不是大家觉得是读取记录中的所有字段值?

对于 selete * 这条语句来说是这个意思,但是在 count(*) 中并不是这个意思。

count(\*) 其实等于 count(0),也就是说,当你使用 count(*) 时,MySQL 会将 * 参数转化为参数 0 来处理。
图片

所以,count(*) 执行过程跟 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)操作,没有性能差异。

而且 MySQL 会对 count(*) 和 count(1) 有个优化,如果有多个二级索引的时候,优化器会使用key_len 最小的二级索引进行扫描。

只有当没有二级索引的时候,才会采用主键索引来进行统计。

count(字段) 执行过程是怎样的?

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

用下面这条语句作为例子:

//name不是索引,普通字段
select count(name) from t_order;

对于这个查询来说,会采用全表扫描的方式来计数,所以它的执行效率是比较差的。

图片

小结

count(1)、 count(*)、 count(主键字段)在执行的时候,如果表里存在二级索引,优化器就会选择二级索引进行扫描。

所以,如果要执行 count(1)、 count(*)、 count(主键字段) 时,尽量在数据表上建立二级索引,这样优化器会自动采用 key_len 最小的二级索引进行扫描,相比于扫描主键索引效率会高一些。

再来,就是不要使用 count(字段) 来统计记录个数,因为它的效率是最差的,会采用全表扫描的方式来统计。如果你非要统计表中该字段不为 NULL 的记录个数,建议给这个字段建立一个二级索引。

二. 为什么要通过遍历的方式来计数?

你可以会好奇,为什么 count 函数需要通过遍历的方式来统计记录个数?

我前面将的案例都是基于 Innodb 存储引擎来说明的,但是在 MyISAM 存储引擎里,执行 count 函数的方式是不一样的,通常在没有任何查询条件下的 count(*),MyISAM 的查询速度要明显快于 InnoDB。

使用 MyISAM 引擎时,执行 count 函数只需要 O(1 )复杂度,这是因为每张 MyISAM 的数据表都有一个 meta 信息有存储了row_count值,由表级锁保证一致性,所以直接读取 row_count 值就是 count 函数的执行结果。

而 InnoDB 存储引擎是支持事务的,同一个时刻的多个查询,由于多版本并发控制(MVCC)的原因,InnoDB 表“应该返回多少行”也是不确定的,所以无法像 MyISAM一样,只维护一个 row_count 变量。

举个例子,假设表 t_order 有 100 条记录,现在有两个会话并行以下语句:

图片

在会话 A 和会话 B的最后一个时刻,同时查表 t_order 的记录总个数,可以发现,显示的结果是不一样的。所以,在使用 InnoDB 存储引擎时,就需要扫描表来统计具体的记录。

而当带上 where 条件语句之后,MyISAM 跟 InnoDB 就没有区别了,它们都需要扫描表来进行记录个数的统计。

三. 如何优化 count(*)?

如果对一张大表经常用 count(*) 来做统计,其实是很不好的。

比如下面我这个案例,表 t_order 共有 1200+ 万条记录,我也创建了二级索引,但是执行一次 select count(*) from t_order 要花费差不多 5 秒!
图片

面对大表的记录统计,我们有没有什么其他更好的办法呢?

*第一种,近似值*

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

这时,我们就可以使用 show table status 或者 explain 命令来表进行估算。

执行 explain 命令效率是很高的,因为它并不会真正的去查询,下图中的 rows 字段值就是 explain 命令对表 t_order 记录的估算值。图片

第二种,额外表保存计数值

如果是想精确的获取表的记录总数,我们可以将这个计数值保存到单独的一张计数表中。

当我们在数据表插入一条记录的同时,将计数表中的计数字段 + 1。也就是说,在新增和删除操作时,我们需要额外维护这个计数表。

四. 总结

 1、从执行结果上分析:

  (1)、count(0)、count(1)和count(*)不会过滤空值

  (2)、count(列名)会过滤空值

 2、从执行效率上分析:

   count(*)=count(0)=count(1)>count(主键字段)>count(非主键字段)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/351814.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

英伟达发布《永劫无间》最新显卡驱动更新,驱动人生升级教程

驱动人生上次给大家推荐了国产游戏之光——《永劫无间》没想到广受各位游戏迷的喜爱! 这次英伟达发布了 GeForce 471.68 WHQL 驱动永劫无间的迷弟迷妹们千万不要错过! 此次驱动更新为游戏《永劫无间》做了优化高帧率畅玩这款游戏 下面驱动人生给大家po出永劫无间游戏最新的配…

如何清理驱动人生的新闻弹窗

前言:驱动人生的弹窗太***了,我搜了好久才找到解决的方法,但是治标不治本,就算删了驱动人生弹新闻的newscenter的文件夹,只要Andrea RT Filters Service启动了,它就又回来了 操作步骤(截图是win…

驱动人生病毒清除教程

首先,该病毒会通过永恒之蓝漏洞、域控PSEXEC、SMB爆破、MSSQL爆破进行传播,在清除之前,需要先确保打上了MS17-010补丁、域控服务器安全、更换高强度密码、更换高强度MSSQL密码。 杀死病毒进程 病毒进程svchost下的一大串可疑进程&#xff0…

开始自己的驱动人生

对一个从学.NET的我来说,学习底层驱动开发,无疑是一个挑战,不管怎么样,既然选择,既然向往,既然喜爱,起码现在我有信息能学下去。 也希望能够学好,但愿以后不要为自己的选择而后悔………

坚守,一个烂俗的词,驱动人生带它走过了15年

2022年是驱动人生走过的第15个年头,在这15年间有创业初期的摸爬滚打,有与困难你来我往的过招,有精益求精的技术迭代,也有一代代驱动成员不求回音的坚守。 在这个特殊的日子里,驱动人生想给大家分享一个关于“坚守”的…

驱动人生深度扫描功能上线!使用感怎么样?

好秃然!刚刚还是全绿的电脑,怎么又出故障了? 快看看驱动扫描是不是有漏网之鱼! 在工作、学习或娱乐的过程中,电脑早已成为了我们必不可少的伙伴(也有可能是老婆)。 电脑由多种硬件设备构成&am…

性能起飞!驱动人生带你了解AMD FSR3.0及显卡驱动

驱动人生获悉,AMD方面带来了好消息,被称之为AMD游戏技术之光的FSR 3.0就要在3月底面市了。 FSR即FidelityFX超分辨率,一项在不损失图像质量和图形细节的情况下提高游戏性能的技术。而FSR除了为AMD显卡提供支持外,NVIDIA以及Intel…

驱动人生国庆宅家指南,这些游戏值得一刷!

担心国庆人从众,堵车堵到人发疯? 做一个快乐游戏宅也未尝不可!(不是我没人约的意思) 驱动人生就来给大家推荐5个国庆上新且值得一玩的游戏吧!还有新驱动大幅度提升游戏体验哦!找驱动会员好物&a…

网络货运平台的服务对象有哪些?

网络货运平台源码 中国物流行业中的货主、司机在空运、高库存、低周转等方面浪费了大量的能耗,网络货运平台为货主找车(托运人)、司机找货(实际承运人)提供了高效便捷的解决方案,也是平台服务的主要对象。…

【FMC129】 基于JESD204B接口的8通道125MSPS 16位AD采集FMC子卡

板卡概述 FMC129是一款8通道125MHz采样率16位AD采集FMC子卡,符合VITA57.1规范,可以作为一个理想的IO模块耦合至FPGA前端,8通道AD通过高带宽的FMC连接器(HPC)连接至FPGA从而大大降低了系统信号延迟。 该板卡支持板上可编…

长尾词挖掘,长尾词的优化方法有哪些

我们都知道,长尾词能给我们带来较高的流量和转化率,且优化难度低,成本低。今天就来分享长尾词的优化方法。 首先需要挖掘长尾词,挖掘长尾词的方法以下3种比较实用: 1、使用长尾词挖掘工具 可以通过第三方工…

【工程实践】python 设置值为列表的字典

1.问题描述 在整理航班数据时,需要整理成key-value方便处理。比如,北京有大兴机场、首都机场。希望处理成北京:[大兴机场,首都机场]的形式。 airports [北京/首都国际机场,北京/首都机场,北京/大兴国际机场,北京/大兴机场,天津/滨海国际机场,天津/滨海机…

Springboot +spring security,基于默认数据库模型实现授权

一.简介 上一篇文章中讲解了如何基于内存模型来实现授权,在这种模型里,用户的信息是保存在内存中的。但是,保存在内存中的信息,是无法持久化的,也就是程序一旦关闭,或者断电等情况发生,内存中的…

如何给apk安装包去毒,避免被识别为病毒和木马

本文来源:安卓修改大师 如果您的应用经常被识别为病毒或者木马,将大大影响应用的推广,更影响您的收益。各种安卓平台的安全软件的监管规则越来越严格,您的应用可能一不小心就会进入病毒库,被识别为有害应用。有没有更…

中了计算机病毒改怎么办,计算机中病毒了怎么办?清除计算机病毒方法有哪些...

计算机中病毒了怎么办?清除计算机病毒方法有哪些。当我们的计算机中了病毒是,该怎么样去清除呢?下面由学习啦小编给你做出详细的清除计算机病毒方法介绍!希望对你有帮助! 清除计算机病毒方法一: 1、全盘搜该文件,删除;[startup.x…

安卓现盗号木马 威胁网银盗刷

最近,某移动安全实验室捕获到一类高度危险的微信盗号木马,多个安卓手机应用中捆绑了该木马,手机中毒后微信帐号会被盗,严重威胁微信钱包及微信关联的网银资金安全,目前已有上千名用户受害。 一个不幸中的万幸是&#x…

SpringBoot3-基础配置和多环境开发

1. 配置文件格式 提供三种属性配置方式,当三个配置文件都有,加载顺序从前至后 示例第二种(主要也是用这个): 2. yaml格式 3. yaml读取数据格式的三种方式 第一种,使用Value读取单一属性数据 Value("${…

病毒木马防御与分析实战

《病毒木马防御与分析》系列以真实的病毒木马(或恶意程序)为研究对象,通过现有的技术手段对其分析,总结出它的恶意行为,进而制定出相应的应对方法,对其彻底查杀。当然,因为我个人水平的有限&…

病毒木马防御与分析实战

《病毒木马防御与分析》系列以真实的病毒木马(或恶意程序)为研究对象,通过现有的技术手段对其分析,总结出它的恶意行为,进而制定出相应的应对方法,对其彻底查杀。当然,因为我个人水平的有限&…

病毒木马防御与分析

病毒木马防御与分析 病毒包和工具包下载:Github 一.前言二.建立对手动查杀病毒技术的正确认识 1.病毒分析方法2.病毒查杀步骤3.必备知识 * 1) 熟悉windows系统进程 * 2) 熟悉常见端口与进程对应关系 * 3) 熟悉windows自带系统服务 * 4) 熟悉注册表启动项位置三.详解Windows随机…