当前位置: 首页 > news >正文

MySQL中COUNT(\*)、COUNT(1)和COUNT(column),到底用哪个?

在这里插入图片描述

前段时间做项目的Code Review,给团队成员强调了一点规则:判断一条数据是否存在时,不要查询列表之后,比较列表长度是否大于0来判断数据是否存在,而是要用COUNT语句直接查询符合条件的条数

此时,有同学提出一个很好的问题:在使用COUNT语句时,应该使用COUNT(*)COUNT(1),还是COUNT(column)呢?这篇文章就带大家重新梳理一下这三者的区别。

COUNT查询的性能排序

首先,直接给出结论:

COUNT(*) = COUNT(1) > COUNT(id,主键字段) > COUNT(字段)

所以,一般情况下直接使用COUNT(*)即可。

这可能很反直觉,因为通常我们在执行SELECT语句时有一个基本规则,需要使用哪些字段尽量在SELECT关键词后明确指出,而不是直接查询出所有的字段,比如SELECT * FROM table_a

关于最终的结论,在阿里巴巴开发手册中也有明确的【强制】说明:

【强制】不要使用COUNT(列名)或COUNT(常量)来替代COUNT(),COUNT()是SQL92定义的标准统计行数的语法,跟数据库无关,跟NULL和非NULL无关。
说明:COUNT(*)会统计值为NULL的行,而COUNT(列名)不会统计此列为NULL值的行。

下面我们来分析一下为什么会得出上述结论。

COUNT(*) 与 COUNT(1)比较

在MySQL的官方文档中是这样介绍COUNT函数的:

img

也就是说,COUNT(expr) 函数会返回SELECT语句检索的行中expr的值不为NULL的数量,结果是一个BIGINT值。如果查询结果没有命中任何记录,则返回0;需要注意的是COUNT(*) 的统计结果中,会包含值为NULL的行数。

在文档的后面,还有一段专门关于COUNT(*)COUNT(1)性能的说明:

img

在上面的描述中,明确指出了:InnoDB 对SELECT COUNT(*)SELECT COUNT(1)操作的处理方式完全相同,两者在性能上没有区别。

对于MyISAM表,COUNT(*) 操作经过优化,在以下情况下可以非常快速地返回结果:查询涉及的仅为一张表、不检索其他列,并且没有 WHERE 子句。例如:

mysql> SELECT COUNT(*) FROM student;

这种优化仅适用于MyISAM表,因为该存储引擎会存储准确的行数(row count),并且可以快速访问。至于COUNT(1),只有在第一列被定义为NOT NULL 时,才会享受相同的优化。

通过官方文档的说明,可以得出一个明确的结论:在InnoDB表的情况下,COUNT(*)COUNT(1)的操作是一样的,在MyISAM表的情况下,COUNT(*) 相对于COUNT(1)要么效果一样,要么COUNT(*) 更优。

这也印证了最开始的结论:一般情况下直接使用COUNT(*)即可,在大多数情况下,COUNT(*)COUNT(1)是一样的,在性能上没有差别。

COUNT()函数的含义

COUNT()是一个聚合函数,聚合函数有个特点,NULL值是不参与聚合函数计算的。而函数的参数不仅可以是字段名,也可以是其他任意表达式。

当使用COUNT(name) 时,name字段为一个表达式,底层会统计name 字段不为NULL的记录,也就是说会进行全表扫描,name不为NULL时,就会将变量count + 1。

在《高性能Mysql》一书中对COUNT()函数的作用介绍如下:

COUNT()是一个特殊的函数,有两种非常不同的作用:它可以统计某个列值的数量,也可以统计行数。在统计列值时要求列值是非空的(不统计NULL)。如果在COUNT()的括号中指定了列或者列的表达式,则统计的就是这个表达式有值的结果数。因为很多人对NULL理解有问题,所以这里很容易产生误解。

COUNT()的另一个作用是统计结果集的行数。当MySOL确认括号内的表达式值不可能为空时,实际上就是在统计行数。最简单的就是当使用COUNT(*)时,这种情况下通配符并不会像我们猜想的那样扩展成所有的列,实际上,它会忽略所有的列而直接统计所有的行数。

一个最常见的错误就是,在括号内指定了一个列却希望统计结果集的行数。如果希望知道的是结果集的行数,最好使用COUNT(*),这样写意义清晰,性能也会很好。

通过上述分析我们可以知道,COUNT(column)是统计非空列的行数,它也会遍历整张表,然后会对列对应的值做非空判断,非空的字段进行个数累加。当然这是列为主键索引时的操作。如果列不为主键索引时,那么查询时还需要进行回表操作,再根据主键获取数据,无疑又增加了一次IO,在性能上其实是不如COUNT(*)COUNT(1)的。

至此,我们可以进一步得出结论:

COUNT(*) = COUNT(1) > COUNT(主键) > COUNT(非主键列)

使用建议

如果要获取一张表的确切行数,可以是优先使用使用 COUNT(*) 获取行数,这样写法清晰,性能较好,它也是SQL92定义的标准统计行数的语法,MySQL对其做了优化,尤其对于InnoDB表的优化更为明显。

同时,要避免使用 COUNT(column) 统计行数,除非你真的需要统计该列非空值的数量,否则容易产生误解。

http://www.lryc.cn/news/610076.html

相关文章:

  • 从零认识OpenFlow
  • 【SAM】Segment Anything 论文翻译笔记
  • opencv引入libavif
  • 模拟IC设计提高系列8-运算跨导放大器OTA Operational Transconduct Amplifiers
  • 家事速配西安项目启动会圆满举行,开启社区服务新篇章
  • 决策树(回归树)全解析:原理、实践与应用
  • 【动态规划 | 回文字串问题】动态规划解回文问题的核心套路
  • 打卡day28
  • Memcached缓存与Redis缓存的区别、优缺点和适用场景
  • Java 大视界 -- Java 大数据在智能交通智能停车诱导与车位共享优化中的应用(381)
  • 【C#】操作Execl和Word文件-1
  • orchestrator部署
  • 11.Linux 权限管理,控制对文件的访问(ACL)
  • git操作命令和golang编译脚本
  • 【Spring】SpringBoot 自动配置,@ComponentScan、@Import、ImportSelector接口
  • 【QT】安装与配置
  • 计量学基础 - (二)计量单位制
  • NX982NX984美光固态闪存NX992NY102
  • 高速信号设计之 PCIe6.0 篇
  • Linux之Shell脚本快速入门
  • 【2025最新】Spring Boot + Spring AI 玩转智能应用开发
  • 微服务的编程测评系统10-竞赛删除发布-用户管理-登录注册
  • 雷达系统工程学习:自制极化合成孔径雷达无人机
  • Flask全栈入门:打造区块链艺术品交易所
  • Oracle 定时任务相关
  • Tomcat虚拟主机配置详解和多实例部署
  • k8s的毫核
  • 太阳光模拟器塑料瓶暴晒试验
  • Vue2实现docx,xlsx,pptx预览
  • P1002 [NOIP 2002 普及组] 过河卒