COUNT(1) 和 COUNT(*) COUNT(字段) 傻傻分不清

2023-11-17

写 SQL 的时候突然想到一个问题:COUNT(1) 和 COUNT(*) 有啥区别?COUNT(字段) 呢?

在数据库的增删改查操作中,使用最频繁的就是查询操作。而在所有查询操作中,统计数量操作更是经常被用到。

关于数据库中行数统计,无论是MySQL还是Oracle,都有一个函数可以使用,那就是COUNT

但是,就是这个常用的COUNT函数,却暗藏着很多玄机,尤其是在面试的时候,一不小心就会被虐。不信的话请尝试回答下以下问题:

1、COUNT有几种用法?

2、COUNT(字段名)和COUNT(*)的查询结果有什么不同?

3、COUNT(1)和COUNT(*)之间有什么不同?

4、COUNT(1)和COUNT(*)之间的效率哪个更高?

5、为什么《阿里巴巴Java开发手册》建议使用COUNT(*)

6、MySQL的MyISAM引擎对COUNT(*)做了哪些优化?

7、MySQL的InnoDB引擎对COUNT(*)做了哪些优化?

8、上面提到的MySQL对COUNT(*)做的优化,有一个关键的前提是什么?

9、SELECT COUNT(*) 的时候,加不加where条件有差别吗?

10、COUNT(*)、COUNT(1)和COUNT(字段名)的执行过程是怎样的?

以上10道题,如果您可以全部准确无误的回答的话,那说明你真的很了解COUNT函数了,如果有哪些知识点是不了解的,那么本文正好可以帮你答疑解惑。


1、认识COUNT

关于COUNT函数,在MySQL官网中有详细介绍:

img

简单翻译一下:

1、COUNT(expr) ,返回SELECT语句检索的行中expr的值不为NULL的数量。结果是一个BIGINT值。

2、如果查询结果没有命中任何记录,则返回0

3、但是,值得注意的是,COUNT(*) 的统计结果中,会包含值为NULL的行数。

即以下表记录

create table #bla(id int,id2 int)
insert #bla values(null,null)
insert #bla values(1,null)
insert #bla values(null,1)
insert #bla values(1,null)
insert #bla values(null,1)
insert #bla values(1,null)
insert #bla values(null,null)

使用语句count(*),count(id),count(id2)查询结果如下:

select count(*),count(id),count(id2)
from #bla
results 7 3 2

除了COUNT(id)COUNT(*)以外,还可以使用COUNT(常量)(如COUNT(1))来统计行数,那么这三条SQL语句有什么区别呢?到底哪种效率更高呢?为什么《阿里巴巴Java开发手册》中强制要求不让使用 COUNT(列名)COUNT(常量)来替代 COUNT(*)呢?

img


2、COUNT(列名)、COUNT(常量)和COUNT(*)之间的区别

前面我们提到过COUNT(expr)用于做行数统计,统计的是expr不为NULL的行数,那么COUNT(列名)COUNT(常量)COUNT(*)这三种语法中,expr分别是列名常量*

那么列名常量*这三个条件中,常量 是一个固定值,肯定不为NULL。*可以理解为查询整行,所以肯定也不为NULL,那么就只有列名的查询结果有可能是NULL了。

所以, COUNT(常量)COUNT(\*)表示的是直接查询符合条件的数据库表的行数。而COUNT(列名)表示的是查询符合条件的列的值不为NULL的行数。

除了查询得到结果集有区别之外,COUNT(*)相比COUNT(常量)COUNT(列名)来讲,COUNT(*)是SQL92定义的标准统计行数的语法,因为他是标准语法,所以MySQL数据库对他进行过很多优化。

SQL92,是数据库的一个ANSI/ISO标准。它定义了一种语言(SQL)以及数据库的行为(事务、隔离级别等)。


3、COUNT(*)的优化

前面提到了COUNT(*)是SQL92定义的标准统计行数的语法,所以MySQL数据库对他进行过很多优化。那么,具体都做过哪些事情呢?

这里的介绍要区分不同的执行引擎。MySQL中比较常用的执行引擎就是InnoDB和MyISAM。

MyISAM和InnoDB有很多区别,其中有一个关键的区别和我们接下来要介绍的COUNT(*)有关,那就是MyISAM不支持事务,MyISAM中的锁是表级锁;而InnoDB支持事务,并且支持行级锁。

因为MyISAM的锁是表级锁,所以同一张表上面的操作需要串行进行,所以,MyISAM做了一个简单的优化,那就是它可以把表的总行数单独记录下来,如果从一张表中使用COUNT(*)进行查询的时候,可以直接返回这个记录下来的数值就可以了,当然,前提是不能有where条件。

MyISAM之所以可以把表中的总行数记录下来供COUNT(*)查询使用,那是因为MyISAM数据库是表级锁,不会有并发的数据库行数修改,所以查询得到的行数是准确的。

但是,对于InnoDB来说,就不能做这种缓存操作了,因为InnoDB支持事务,其中大部分操作都是行级锁,所以可能表的行数可能会被并发修改,那么缓存记录下来的总行数就不准确了

但是,InnoDB还是针对COUNT(*)语句做了些优化的。

在InnoDB中,使用COUNT(*)查询行数的时候,不可避免的要进行扫表了,那么,就可以在扫表过程中下功夫来优化效率了。

从MySQL 8.0.13开始,针对InnoDB的SELECT COUNT(*) FROM tbl_name语句,确实在扫表的过程中做了一些优化。前提是查询语句中不包含WHERE或GROUP BY等条件。

我们知道,COUNT(*)的目的只是为了统计总行数,所以,他根本不关心自己查到的具体值,所以,他如果能够在扫表的过程中,选择一个成本较低的索引进行的话,那就可以大大节省时间。

我们知道,InnoDB中索引分为聚簇索引(主键索引)和非聚簇索引(非主键索引),聚簇索引的叶子节点中保存的是整行记录,而非聚簇索引的叶子节点中保存的是该行记录的主键的值。

所以,相比之下,非聚簇索引要比聚簇索引小很多,所以MySQL会优先选择最小的非聚簇索引来扫表。所以,当我们建表的时候,除了主键索引以外,创建一个非主键索引还是有必要的。

至此,我们介绍完了MySQL数据库对于COUNT(*)的优化,这些优化的前提都是查询语句中不包含WHERE以及GROUP BY条件。


4、COUNT(*)和COUNT(1)

介绍完了COUNT(*),接下来看看COUNT(1),对于,这二者到底有没有区别,网上的说法众说纷纭。

有的说COUNT(*)执行时会转换成COUNT(1),所以COUNT(1)少了转换步骤,所以更快。

还有的说,因为MySQL针对COUNT(*)做了特殊优化,所以COUNT(*)更快。

那么,到底哪种说法是对的呢?看下MySQL官方文档是怎么说的:

InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.

画重点:same way , no performance difference所以,对于COUNT(1)和COUNT(*),MySQL的优化是完全一样的,根本不存在谁比谁快!

那既然COUNT(*)COUNT(1)一样,建议用哪个呢?

建议使用COUNT(*)!因为这个是SQL92定义的标准统计行数的语法,而且本文只是基于MySQL做了分析,关于Oracle中的这个问题,也是众说纷纭的呢。


5、COUNT(字段)

最后,就是我们一直还没提到的COUNT(字段),他的查询就比较简单粗暴了,就是进行全表扫描,然后判断指定字段的值是不是为NULL,不为NULL则累加。

相比COUNT(*)COUNT(字段)多了一个步骤就是判断所查询的字段是否为NULL,所以他的性能要比COUNT(*)慢。


6、总结

本文介绍了COUNT函数的用法,主要用于统计表行数。主要用法有COUNT(*)COUNT(字段)COUNT(1)

因为COUNT(*)是SQL92定义的标准统计行数的语法,所以MySQL对他进行了很多优化,MyISAM中会直接把表的总行数单独记录下来供COUNT(*)查询,而InnoDB则会在扫表的时候选择最小的索引来降低成本。当然,这些优化的前提都是没有进行where和group的条件查询。

在InnoDB中COUNT(*)COUNT(1)实现上没有区别,而且效率一样,但是COUNT(字段)需要进行字段的非NULL判断,所以效率会低一些。

因为COUNT(*)SQL92定义的标准统计行数的语法,并且效率高,所以请直接使用COUNT(*)查询表的行数!


参考链接:MySQL的COUNT语句,竟然都能被面试官虐的这么惨!?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

COUNT(1) 和 COUNT(*) COUNT(字段) 傻傻分不清 的相关文章

  • 选择获取与 MySQL Group 中 max 对应的整行

    当我使用Max使用后查找特定 MySQL 组中字段的最大值GROUP BY 是否可以获取包含最大值的整行 我在处理一些论坛代码时偶然发现了这个线程 我想获取每个线程的最新帖子并将其显示在特定板的线程列表中 Quassnoi上面的回答对我非常
  • 查询为空 Node Js Sequelize

    我正在尝试更新 Node js 应用程序中的数据 我和邮递员测试过 我的开发步骤是 从数据库 MySQL 获取ID为10的数据进行更新 gt gt 未处理的拒绝SequelizeDatabaseError 查询为空 我认识到 我使用了错误的
  • Oracle REGEXP_INSTR() 和“a-z”字符范围与预期不匹配

    我想用REGEXP INSTR 在 oracle 数据库中检查小写 大写字符 我知道 upper and lower POSIX 字符类 但我选择了a z这给了我非常奇怪的结果 我不明白 有人可以解释一下吗 SELECT REGEXP IN
  • 使用 PHP 将 latin1_swedish_ci 转换为 utf8

    我有一个数据库 里面充满了类似的值 Dhaka 应该是 Dhaka 因为我在创建数据库时没有指定排序规则 现在我想修复它 我无法从最初获取数据的地方再次获取数据 所以我在想是否可以在 php 脚本中获取数据并将其转换为正确的字符 我已将数据
  • 无法从我的 java 应用程序访问 mysql 数据库(在 AWS 实例上运行)

    我有一个在 AWS EC2 Ubuntu 实例上运行的 xampp 服务器 并且那里有一个名为 androiddb 的数据库 我可以通过在导航器中写入来访问数据库http public ip phpmyadmin http public i
  • MySQL存储过程变量作为表名连接

    我想在存储过程中执行以下查询而不准备查询 因为这给我带来了 OUT 传回参数的问题 DELIMITER CREATE PROCEDURE Test IN CID BIGINT 20 IN IDs LONGTEXT BEGIN EXECUTE
  • MySQL查询,删除所有空格

    我有一个不寻常的查询 这让我现在陷入困境 表字段有 id bigint 20 name varchar 255 desc text 有许多记录具有相同的名称和 desc 但 desc 的单词之间有一些额外的空格 like 1 t1 hell
  • SQLite SQL 查询出现问题[重复]

    这个问题在这里已经有答案了 我正在尝试在 SQLite 3 中运行以下查询 SELECT DISTANCE latitude longitude AS distance FROM country WHERE id NOT LIKE HAVI
  • 就SQL注入而言,哪种sql查询更安全

    我有两个 SQL 查询正在尝试更新sup and opp每次调用查询时 值分别为 1 和 1 第一个查询 query update disc set sup sup opp opp where did did int sup getnoof
  • 删除、截断或删除以清理 MySQL 中的表

    我正在尝试清理表格 但没有摆脱表格的实际结构 我有一个id自动递增的列 我不需要保留ID号 但我确实需要它来保持其自动递增的特性 我发现了删除和截断 但我担心其中之一会完全删除整个表 从而使未来的插入命令变得无用 如何从表中删除所有记录以便
  • 一张表中按最大日期过滤重复行的 SQL 查询

    我有一个 SQL 数据库 persons 它具有基于 IDNum 列的重复条目 我需要查询条目并仅根据最新创建日期显示行或重复条目 这是查询 SELECT IDNum PersonPGUID CreatedDateTime FirstNam
  • MySQL 中布尔值的 TINYINT 与 ENUM(0, 1)

    MyISAM 表和 MySQL 5 1 中具有 0 和 1 值的 Tinyint 或 ENUM 0 1 哪个更好 您可以使用BIT 1 如中提到的MySQL 5 1 参考 http dev mysql com doc refman 5 1
  • 使用 SQL 完全复制 postgres 表

    免责声明 这个问题和栈溢出问题类似here https stackoverflow com questions 198141 copy a table including indexes in postgres 但这些答案都不适用于我的问题
  • 在 BIRT 中输入参数后更新数据集查询

    在 BIRT 报告设计中传递参数后 如何更改或更新数据集的查询 详细说明 我有一个如下所示的查询 WHERE 该参数标记可以保存不同的值 在用户输入参数后 它看起来像这样 例如 WHERE column name 1 or WHERE co
  • 如何检查一个值是否已经存在以避免重复?

    我有一个 URL 表 但我不想要任何重复的 URL 如何使用 PHP MySQL 检查给定 URL 是否已在表中 如果您不想重复 可以执行以下操作 添加唯一性约束 use REPLACE http dev mysql com doc ref
  • 数据读取过程中遇到致命错误

    我正在进行定期更新表扫描 Using connect1 As New MySqlConnection ConnectLocalhost serverString connect1 Open Dim cmd New MySqlCommand
  • MySQL 正在将我的时间戳值转换为 0000-00-00

    我是 PHP 新手 目前仍在学习中 我认为我的注册表有问题 username password email全部成功插入MySQL registered and last seen不要 我以为我正在使用getTimestamp 错了 但它呼应
  • Innodb页面大小设置

    在innodb中 页面大小默认为16kb 如何将页面大小设置为 8kb 是否有在源编译步骤中设置的选项 您不需要在源编译步骤中指定页面大小 MySQL 5 6 及更高版本支持不同的页面大小 无需重新编译 但是 您必须在初始化 InnoDB
  • 在 Django 查询中使用 .extra(select={...}) 引入的值上使用 .aggregate() ?

    我正在尝试计算玩家每周玩游戏的次数 如下所示 player game objects extra select week WEEK games game date aggregate count Count week 但姜戈抱怨说 Fiel
  • MYSQL 按喜欢/不喜欢和受欢迎程度排序

    我有评论表 其中包括喜欢和不喜欢的内容 现在我在正确的顺序上遇到了问题 实际上 我的系统在顶部显示了最多点赞的评论 我正在 youtube 上寻找类似系统的东西 这意味着 100like 100dislikes 的评论的顺序高于 1 1 我

随机推荐

  • swagger注释API详细说明

    API详细说明 注释汇总 作用范围 API 使用位置 对象属性 ApiModelProperty 用在出入参数对象的字段上 协议集描述 Api 用于controller类上 协议描述 ApiOperation 用在controller的方法
  • Apache服务安全加固及Apache优化

    转载来源 https help aliyun com knowledge detail 52981 html 一 账号设置 以专门的用户帐号和用户组运行 Apache 服务 1 根据需要 为 Apache 服务创建用户及用户组 如果没有设置
  • python+selenium自动化测试通过cookie绕过登录验证

    前言 之前记录过通过截图获取验证码的方式实现登录 但目前存在识别不准确的情况 因此有本篇通过cookie绕过登录验证的方法 绕过登录后 可以便于对系统的功能界面进行自动化测试设计 一 关于cookie的一些认知 1 浏览器的缓存有两种机制
  • C++ 中sort排序改变数值相同的数据相对位置的解决办法

    今天给大家介绍个超级好用的知识 写了那么多的排序 但是其实C 里封装有排序函数 而且功能非常强大 sort函数有sort stable sort 和partial sort sort 函数是对给定区间的元素进行排序 但是会改变值相同的元素的
  • Centos7搭建RabbitMQ集群及单机多节点部署

    安装基本环境 yum y install wget vim bash completion lrzsz nmap telnet tree net tools bind utils lsof ntpdate iotop erlang环境 wg
  • 深入理解计算机系统-笔记

    计算机系统漫游 程序 程序的生命周期从一个源程序 源文件 开始 即程序员利用编辑器创建并保存的文本文件 如文件名为hello c的c语言程序 源程序是由0和1组成的位序列 8个位被组织成一组 称为字节 每个字节表示程序中的某个文本字符 这种
  • css布局 - 垂直居中布局的一百种实现方式(更新中...)

    首先将垂直居中的现象和实现方式两大方向细分类如下 接下来逐条累加不同情况下的垂直居中实现 目录 一 父元素高度固定时 单行文本 图片的垂直居中 1 line height行高简单粗暴实现法 line height Npx N 与元素高度相同
  • parted 分区与磁盘扩容(二)

    前 LVM分区管理是对后续扩容磁盘做铺垫的 现在2TB的硬盘都非常常见了 对于超过2TB的硬盘分区 需要使用parted命令进行操作 fdisk只可以操作2TB之内的 本次教程教你们如何轻松实现2T以上和2T以下磁盘的分区及扩容 一 首先要
  • avalon框架中ms-visible和ms-if的区别

    在avalon的官方教程中说 ms visible的作用是使元素在一定条件下隐藏 不显示 ms if 同样隐藏 但它是将元素移出DOM 这个功能直接影响到CSS empty伪类的渲染结果 那么 什么是伪类 它与class id等功能类似 也
  • 利用VTK显示PLY网格模型文件

    define vtkRenderingCore AUTOINIT 2 vtkRenderingOpenGL2 vtkInteractionStyle include
  • 使用Idea打开Maven项目的正确姿势

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 在学习网上大神们的源码过程中 经常有一些打包好的项目可以提供给自己参考学习 其中不乏一些maven项目 因为自己使用的开发环境是Idea Gradle 对于Maven虽有耳
  • 模型设计总结(1)

    用单变量线性时间序列预测模型预测股价走势有一定的局限性 因此 为了充分利用时间序列的特性数据序列 深入挖掘数据特征 提高数据质量为了提高股票价格预测的准确性 基于CNN LSTM的股票价格预测方法进行股票次日收盘价预测 卷积神经网络 CNN
  • Pandas 使用ExcelWriter实现覆盖文件操作

    if sheet exists replace 这段代码主要实现的作用是 多次使用同一个文件 创建sheet时 但已存在同样的sheet名 进行覆盖操作 writer pd ExcelWriter result file path engi
  • 【阅读随笔】Modularized Control Synthesis for Complex Signal Temporal Logic Specifications

    又是一篇有关STL任务分解的文章 1 Z Zhang and S Haesaert Modularized Control Synthesis for Complex Signal Temporal Logic Specifications
  • 防御第三天

    1 总结当堂NAT与双机热备原理 形成思维导图 2 完成课堂NAT与双机热备实验 fw1
  • PIO操作Excel,通过文件流判断Excel的版本

    import com fasterxml jackson databind exc InvalidFormatException import org apache poi ss usermodel Workbook import org
  • 送书

    又到了周三了 说实话 本来这期想鸽的 上海这边的疫情太严重了 前几期上海这边中奖的粉丝都没办法收货 只能等解封后再安排了 在这里和大家道个歉 希望大家谅解 最后希望在上海的小伙伴们早日渡过难关 像这种一把青菜50块的日子什么时候才是个头啊
  • 推荐七种开源免费的C/C++网络库

    1 ACE 庞大 复杂 适合大型项目 开源 免费 不依赖第三方库 支持跨平台 2 Asio Asio基于Boost开发的异步IO库 封装了Socket 简化基于socket程序的开发 开源 免费 支持跨平台 3 POCO POCO C Li
  • java向上转型思考

    https www cnblogs com bangaj p 5813738 html 下面是对向上转型思考 作用 简化开发 体现类的多态性 保证代码简洁 实现前提 因为java是动态绑定特点 在编译时会编译器会自动找寻到 是子类方法还是父
  • COUNT(1) 和 COUNT(*) COUNT(字段) 傻傻分不清

    写 SQL 的时候突然想到一个问题 COUNT 1 和 COUNT 有啥区别 COUNT 字段 呢 在数据库的增删改查操作中 使用最频繁的就是查询操作 而在所有查询操作中 统计数量操作更是经常被用到 关于数据库中行数统计 无论是MySQL还