MySQL中的count函数

1. COUNT() 是什么?

        在 MySQL 中,COUNT() 是一个聚合函数,用于统计结果集中行的数量。它常见的几种用法包括:

  • COUNT(*):统计结果集中所有行的数量,包括包含 NULL 的行。
  • COUNT(1):统计结果集中所有行的数量,和 COUNT(*) 功能相同。
  • COUNT(字段名):统计结果集中某个字段非 NULL 值的数量。
  • COUNT(主键字段名):统计结果集中某个主键字段非 NULL 值的数量。

简单例子

假设有一个 users 表,数据如下:

idnameage
1Alice25
2BobNULL
3Charlie30
NULLNULL20
  1. COUNT(*)

    SELECT COUNT(*) FROM users;

    结果:4(统计所有行,无论字段是否为 NULL)。

  2. COUNT(id)

    SELECT COUNT(id) FROM users;

    结果:3(统计 id 列非 NULL 值的数量)。

  3. COUNT(DISTINCT age)

    SELECT COUNT(DISTINCT age) FROM users;

    结果:3(去重后的 age 值:25, 30, 20)。

先给结论:

执行效率排序(InnoDB)

方法功能执行过程性能情况
COUNT(*)统计所有行的数量(包括 NULL 行)遍历表或索引,计算所有行数,InnoDB 遍历聚簇索引最高效率,InnoDB 会通过聚簇索引快速扫描
COUNT(1)统计所有行的数量优化器会将其转换为 COUNT(*),功能和过程完全相同COUNT(*) 相同,性能无差异
COUNT(主键字段)统计所有行的数量(主键字段非 NULL通过主键索引扫描,所有主键字段值非 NULL高效,MySQL 会直接使用主键索引进行扫描
COUNT(字段)统计指定字段非 NULL 的行数如果字段有索引,使用索引扫描;没有索引则需要全表扫描如果字段有索引,效率较高;无索引时性能较差

具体原因解释:

  1. COUNT(*)

    • COUNT(*) 的效率在 InnoDB 中通常最高,因为它会遍历整个表或索引计算所有行数。对于 InnoDB,它通常依赖于聚簇索引来获取表的行数,聚簇索引直接将表数据存储在索引叶节点中,避免了额外的查找开销,因此相对高效。
  2. COUNT(1)

    • COUNT(1) 实际上和 COUNT(*) 完全等效。因为 1 是一个常量,不涉及任何字段,MySQL 会优化 COUNT(1)COUNT(*),两者的执行过程是一样的。所以,性能与 COUNT(*) 相同。
  3. COUNT(主键字段)

    • 由于 InnoDB 使用聚簇索引,主键索引包含了表的所有行数据。如果你使用主键字段来计数,MySQL 会利用主键索引来扫描行。相比全表扫描,主键索引扫描通常更高效。因此,COUNT(主键字段) 在 InnoDB 中通常比 COUNT(字段) 更高效。
  4. COUNT(字段)

    • 有索引的字段:如果字段有索引,MySQL 会直接扫描索引来计算非 NULL 的行数,效率较高。
    • 没有索引的字段:如果字段没有索引,MySQL 会进行全表扫描,逐行检查字段值是否为 NULL,性能较差。

总结

对于 InnoDB 引擎:

  • COUNT(*)COUNT(1) 的执行效率是相同的,通常效率最高。
  • COUNT(主键字段) 依赖于主键索引,通常效率也很高,尤其当主键索引可用时。
  • COUNT(字段) 的性能取决于字段是否有索引。如果字段没有索引,效率最低,因为需要全表扫描。

性能排序(InnoDB)

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

2. COUNT(字段) 的执行过程

什么是 COUNT(字段)

COUNT(字段) 用于统计结果集中某个字段值不为 NULL 的行数。
它与 COUNT(*)COUNT(1) 不同,不会统计字段值为 NULL 的行。

COUNT(字段) 的执行流程

假设我们使用以下表和数据:

idnameage
1Alice25
2BobNULL
3Charlie30
NULLNULL20

执行查询:

SELECT COUNT(age) FROM users;
  1. 全表扫描

    • MySQL 遍历表中每一行。
  2. 字段值检查

    • 对于 age 字段,MySQL 检查其值是否为 NULL
    • 如果字段值不为 NULL,计数器加一;如果字段值为 NULL,则跳过。
  3. 结果返回

    • 扫描完成后,计数器的值即为 COUNT(age) 的结果。

对于以上数据,COUNT(age) 的结果是 3,因为 age 字段有 3 行值非 NULL(25、30、20)。

COUNT(字段) 的注意点

  1. COUNT(*)COUNT(字段) 的区别

    • COUNT(*):统计所有行,包括字段值为 NULL 的行。
    • COUNT(字段):只统计字段值非 NULL 的行。

    示例:

    SELECT COUNT(*), COUNT(age) FROM users;

    返回结果:

    COUNT(*)COUNT(age)
    43
    • COUNT(*) 是 4:表中有 4 行。
    • COUNT(age) 是 3age 字段中有 1 个 NULL 值。
  2. 索引的优化

    • 如果字段上存在索引,MySQL 可以直接扫描索引,而无需全表扫描。
    • 对于非索引字段,MySQL 仍需要逐行检查字段值是否为 NULL

小结

  • COUNT(字段) 统计指定字段值不为 NULL 的行数。
  • 它需要逐行检查字段值是否为 NULL,并根据条件增加计数器。
  • 如果表中字段的 NULL 比例较高,COUNT(字段) 的结果可能显著小于 COUNT(*)

3. COUNT(主键字段) 的执行过程

什么是主键字段?

        在 MySQL 中,主键(Primary Key)是表中唯一标识每一行的列或列的组合,它具有以下特点:

  • 每个主键值唯一。
  • 主键列不能为 NULL

假设我们有以下表结构和数据:

CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(50), age INT ); 
INSERT INTO users VALUES (1, 'Alice', 25), (2, 'Bob', NULL), (3, 'Charlie', 30), (4, NULL, 20);

数据如下:

idnameage
1Alice25
2BobNULL
3Charlie30
4NULL20

执行过程:COUNT(id)

SELECT COUNT(id) FROM users;

在执行 COUNT(主键字段) 时,MySQL 的执行过程如下:

  1. 索引查找
    主键字段 id 是一个索引(通常是聚簇索引),因此 MySQL 首先扫描主键索引。

  2. 非空检查
    COUNT(id) 只统计 id 列中非 NULL 的行。因为主键不允许为 NULL,所以表中的所有行都会被计入。

  3. 计数
    每找到一个非 NULL 值,就将计数器加一。

  4. 返回结果
    遍历所有主键后,MySQL 将计数结果返回。

在这个例子中,COUNT(id) 的结果是 4,因为表中每一行的 id 都是非空值。

注意事项

  • 如果表的主键列中所有行都非空(通常是这种情况),那么 COUNT(主键字段) 的结果与 COUNT(*) 的结果相同,但实现方式略有不同(COUNT(*) 包括扫描全表)。

4. COUNT(*) 的执行过程

COUNT(*) 是什么?

  • COUNT(*) 用于统计结果集中所有行的数量,包括 NULL 和非 NULL 值。
  • COUNT(字段名) 不同,它并不关心具体字段的值,只统计表中实际存在的行。

执行过程:COUNT(*)

假设我们有如下表和数据:

idnameage
1Alice25
2BobNULL
3Charlie30
NULLNULL20

SQL 查询:

SELECT COUNT(*) FROM users;
  1. 全表扫描

    • MySQL 对表中的每一行进行扫描,无论行中是否存在 NULL 值,所有行都会被计入。
    • 如果表使用的是 MyISAM 存储引擎,MySQL 会直接读取存储的表行数(更高效);而 InnoDB 引擎则需要遍历表或索引。
  2. 行统计

    • 每遍历一行,计数器加一。
  3. 结果返回

    • 扫描完成后,计数器的最终值即为 COUNT(*) 的结果。

对于以上数据,COUNT(*) 返回的结果是 4,因为表中有 4 行数据。

COUNT(*)COUNT(字段名) 的对比

  • COUNT(*):统计表中所有行,包含 NULL 值。
  • COUNT(字段名):只统计指定字段中非 NULL 的行。

例如:

SELECT COUNT(*), COUNT(name) FROM users;

结果为:

COUNT(*)COUNT(name)
43
  • COUNT(*) 是 4:表中有 4 行。
  • COUNT(name) 是 3name 列中有 1 个 NULL,只统计了非 NULL 的 3 行。

5. COUNT(1) 的执行过程

什么是 COUNT(1)

COUNT(1) 是一种特殊用法,其中 1 并不是表中的列,而是一个常量。
其功能与 COUNT(*) 类似,都用于统计结果集中的行数。

COUNT(1) 的执行流程

假设我们仍然使用以下表和数据:

idnameage
1Alice25
2BobNULL
3Charlie30
NULLNULL20

执行查询:

SELECT COUNT(1) FROM users;
  1. 常量优化

    • 在 SQL 查询优化阶段,MySQL 知道 1 是一个常量,与表中的任何列无关。
    • 它的作用相当于告诉 MySQL:每行都加一个计数,忽略表中的实际列值。
  2. 全表扫描

    • MySQL 扫描表中的所有行,无论是否存在 NULL 值。
  3. 计数

    • 遍历时,对每行都增加计数,无需判断任何字段是否为 NULL
  4. 结果返回

    • 扫描完成后,返回计数结果。

COUNT(1)COUNT(*) 的区别

  1. 功能上

    • 两者完全相同,都会统计结果集中所有的行。
    • 不会因为表中存在 NULL 或其他字段值的不同而有差异。
  2. 性能上

    • MySQL 优化器会将 COUNT(1) 转换为 COUNT(*)
    • 对于 MyISAM 和 InnoDB 引擎,COUNT(1)COUNT(*) 的性能是一样的。
    • 在某些场景中,COUNT(1) 会通过主键或索引更高效地完成计数,但现代 MySQL 的优化器已经能很好地处理两种情况,几乎没有差异。

小结

  • COUNT(*) 是标准写法,语义清晰,通常推荐使用。
  • COUNT(1) 功能完全相同,适合某些开发习惯或历史原因下的场景。
  • 两者性能几乎没有区别,优化器会对它们进行相同的处理。

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

原因分析

        MySQL 的 COUNT() 函数需要准确统计行的数量或字段的非 NULL 数量,这通常需要遍历表中的数据。以下是核心原因:

1. 数据的动态性

        数据库中的数据是动态的,可能随时发生插入、更新或删除。如果 MySQL 不实时遍历表中的数据,可能导致计数结果不准确。尤其是对于 InnoDB 引擎,它没有直接存储精确的行数。

  • InnoDB 的特点

    • 数据存储在聚簇索引中,没有单独的计数记录。
    • 每次执行 COUNT(*)COUNT(字段名),都需要遍历表或索引,确保结果最新。
  • MyISAM 的优化

    • MyISAM 存储引擎会维护一个精确的行数(元数据),执行 COUNT(*) 时可以直接返回行数,而无需遍历。

2. 数据过滤的需要

  • 对于 COUNT(字段名)COUNT(DISTINCT 字段名),需要对数据进行过滤(如排除 NULL 或去重)。
  • MySQL 必须逐行检查数据,判断是否满足计数条件,因此需要遍历数据。

3. 数据分布复杂性

在实际应用中,表可能包含以下情况:

  • 稀疏数据:某些列可能大量为 NULL
  • 非连续主键:主键可能跳跃性增减。
  • 复杂条件:如果查询包含 WHERE 子句(例如 COUNT(*) WHERE age > 20),MySQL 需要根据条件筛选行,因此无法简单依赖已有的统计值。

这些复杂性决定了计数必须遍历表或索引,而无法直接通过元数据实现。

4. 索引的作用

遍历的效率可以通过索引优化。举例:

  • 对于 COUNT(主键字段),MySQL 只需要遍历聚簇索引,因为主键总是唯一且非空。
  • 对于 COUNT(*),如果表中存在合适的覆盖索引,MySQL 也可以通过索引完成统计,而无需扫描整个表。

结论

        遍历表是确保计数准确的核心方式。虽然 MyISAM 引擎通过存储行数可以省去遍历过程,但 InnoDB 的动态数据和多种计数条件决定了遍历是必要的。

7. 如何优化 COUNT(*)

        由于 COUNT(*) 通常需要遍历表或索引,这可能导致性能瓶颈,尤其是当表非常大时。以下是两种主要的优化方法:

方法一:近似值方法

核心思想

        通过统计表的一部分数据,推测出总行数,而不需要精确遍历所有行。

适用场景

  • 对计数结果的要求不是严格的精确值,而是大致估算。
  • 适用于大数据量的表,统计结果不用于事务性场景。

实现方式

  1. 采样统计

    • 从表中抽取一定比例的数据样本,计算样本的行数,然后根据比例推算总行数。
    • 例如:
      SELECT COUNT(*) * 10 AS estimated_count FROM (SELECT * FROM users LIMIT 100) AS sample;
      上例中,从表中抽取 100 行样本,假设表的总行数为 1000,则近似估算总行数为 100 × 10 = 1000
  2. 利用信息_schema 表

    • MySQL 的 information_schema.tables 中存储了表的行数估算值,但对 InnoDB 引擎来说,这个值并非实时精确。
    • 示例:
      SELECT TABLE_ROWS FROM information_schema.tables WHERE TABLE_SCHEMA = 'your_database' AND TABLE_NAME = 'your_table';

       

    • 优点:快速返回行数近似值。
    • 缺点:可能与实际行数有偏差。

优点和缺点

  • 优点:性能非常高,适合对性能敏感但允许一定误差的场景。
  • 缺点:统计结果不够精确,无法满足对数据精确度要求高的场景。

方法二:额外表保存计数值

核心思想

通过维护一个额外的计数表或计数字段,实时存储行的数量。每次插入、更新或删除操作时,自动更新计数值。

适用场景

  • 对计数值的精确性要求较高。
  • 表的更新频率较低(更新频繁时维护计数值的开销较大)。

实现方式

  1. 创建计数表或计数字段

    • 创建一张专门的计数表:
      CREATE TABLE table_counts ( table_name VARCHAR(50) PRIMARY KEY, row_count INT NOT NULL );

       

    • 在表更新时维护计数,例如通过触发器:
      CREATE TRIGGER after_insert_users AFTER INSERT ON users FOR EACH ROW BEGIN UPDATE table_counts SET row_count = row_count + 1 WHERE table_name = 'users'; END;

       

  2. 直接为目标表添加计数字段

    • 在表中增加一个字段 row_count,每次插入或删除时,手动更新这个字段。

优点和缺点

  • 优点:能够精确统计行数,查询时性能极高(无需遍历表)。
  • 缺点:需要额外的存储空间和维护开销;对频繁更新的表可能增加性能负担。

总结

  • 近似值方法 更适合追求性能但对精度要求不高的场景,例如数据分析中的大表。
  • 额外表保存计数值 更适合小表或对计数精度要求高的业务系统。

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

shell(2)永久环境变量和字符串显位

shell(2)永久环境变量和字符串显位 声明! 学习视频来自B站up主 ​泷羽sec​​ 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章 笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习…

基于pytorch使用仿真数据集来训练一个深度学习模型进行相位解包裹

使用 PyTorch 来训练一个深度学习模型进行相位解包裹是一种常见的方法。下面是一个详细的示例,展示如何生成仿真数据集并在 PyTorch 中训练模型。 1. 生成仿真数据集 首先,我们生成一些仿真数据集,包含多个包裹相位图和对应的解包裹相位图。…

使用 Python 的 pdfplumber 库高效解析 PDF 文件

使用 Python 的 pdfplumber 库高效解析 PDF 文件 PDF 文件是日常办公和数据处理中常见的文件格式,而 pdfplumber 是一个专为 PDF 文件解析设计的 Python 库,可以轻松提取文本、表格、图像等内容。本文将介绍 pdfplumber 的基本功能、使用方法&#xff0…

Java实现IP代理池

文章目录 Java实现IP代理池一、引言二、构建IP代理池1、代理IP的获取2、代理IP的验证1. 导入必要的库2. 设置代理IP和端口3. 发起HTTP请求4. 检查请求结果5. 完整的验证方法 注意事项 三、使用IP代理池四、总结 Java实现IP代理池 一、引言 在网络爬虫或者需要频繁请求网络资源…

微服务保护和分布式事务

文章目录 一、微服务保护1.1 微服务保护方案:1.1.1 请求限流:1.1.2 线程隔离:1.1.3 服务熔断: 1.2 Sentinel:1.2.1 介绍和安装:1.2.2 微服务整合: 1.3 请求限流:1.4 线程隔离&#x…

后端 Java发送邮件 JavaMail 模版 20241128测试可用

配置授权码 依赖 <dependency><groupId>javax.mail</groupId><artifactId>javax.mail-api</artifactId><version>1.5.5</version> </dependency> <dependency><groupId>com.sun.mail</groupId><artifa…

MySQL安装与卸载(linux)

MySQL安装与卸载 MySQL8.0.26-安装1. 准备一台Linux服务器2. 下载Linux版MySQL安装包3. 上传MySQL安装包4. 创建目录,并解压5. 安装mysql的安装包6. 启动MySQL服务7. 查询自动生成的root用户密码8. 修改root用户密码9. 创建用户10. 并给root用户分配权限11. 重新连接MySQL MySQ…

LayaBox1.8.4实现自定义3DMesh

实现mesh的原理可参考我写的Unity中的自定义mesh的原理&#xff0c; 碰撞检测算法——分离轴算法在Unity中实现&#xff08;一&#xff09;_unity 自定义高性能碰撞检测方案-CSDN博客 实现可传入shader两张贴图的顶点声明如下&#xff1a; var vertexDeclarationLaya.Vertex…

设置ip和代理DNS的WindowsBat脚本怎么写?

今天分享一个我们在工作时&#xff0c;常见的在Windows中通过批处理脚本&#xff08;.bat 文件&#xff09;来设置IP地址、代理以及DNS 相关配置的示例&#xff0c;大家可以根据实际需求进行修改调整。 一、设置静态IP地址脚本示例 以下脚本用于设置本地连接&#xff08;你可…

施工车辆,工程车类型识别,可识别装载机,搅拌车,挖掘机,拉土车等,支持YOLO,COCO,VOC三种格式带标记

1338总图像数 数据集分割 训练组 87&#xff05; 1170图片 有效集 8% 112图片 测试集 4% 56图片 预处理 自动定向&#xff1a; 已应用 调整大小&#xff1a; 拉伸至 640x640 增强 每个训练示例的输出&#xff1a; 3 旋转&#xff1a; -15 至 15 之间 …

oracle 用户手册

Oracle用户手册 一、Oracle数据库概述 定义与用途 Oracle数据库是一款功能强大的关系型数据库管理系统(RDBMS)。它用于存储和管理大量的结构化数据,广泛应用于企业级应用、金融系统、电商平台等各种需要高效数据处理和存储的场景。例如,银行使用Oracle数据库来存储客户账户…

新版布谷直播软件源码开发搭建功能更新明细

即将步入2025年也就是山东布谷科技专注直播系统开发,直播软件源码出售开发搭建等业务第9年,山东布谷科技不断更新直播软件功能&#xff0c;以适应当前新市场环境下的新要求。山东布谷科技始终秉承初心&#xff0c;做一款符合广大客户需求的直播系统软件。支持广大客户提交更多个…

科技赋能:企业如何通过新技术提升竞争力的策略与实践

引言 在当今瞬息万变的商业环境中&#xff0c;科技的迅猛发展正在重新定义行业的游戏规则。无论是小型企业还是跨国巨头&#xff0c;都感受到数字化转型的迫切需求。过去&#xff0c;企业竞争力更多依赖于成本控制、资源调配或市场覆盖&#xff0c;而如今&#xff0c;新技术的引…

回调函数-一文读懂

回调函数(Callback Function)是指通过函数指针传递给另一个函数的函数。调用者可以在合适的时机(例如事件发生时)调用这个回调函数。回调函数常用于实现一些插件化或动态响应的设计模式,如事件处理、异步编程、函数定制等。 回调函数的基本概念 定义:回调函数是由一个函…

Python编程实例-实现环形缓冲(Ring Buffer)

实现环形缓冲(Ring Buffer) 文章目录 实现环形缓冲(Ring Buffer)1、了解环形缓冲2、环形缓冲工作原理3、代码实现4、总结1、了解环形缓冲 环形缓冲区(Circular Buffer),又称循环缓冲区或环形队列,是一种固定大小的先进先出(FIFO)数据结构。它广泛应用于实时系统、音频处…

项目自动化部署,持续集成/持续交付(CI/CD)工具有那些?他们的优劣势分别是什么?共计15个工具进行对比分析。

项目自动化部署&#xff0c;持续集成/持续交付&#xff08;CI/CD&#xff09;工具有那些&#xff1f;他们的优劣势分别是什么&#xff1f; 主要对比的工具有&#xff1a;Jenkins 、阿里云云效、华为云DevCloud、腾讯云CODING、百度智能云DevOps、 GitLab CI/CD、CircleCI、Trav…

Web登录页面设计

记录第一个前端界面&#xff0c;暑假期间写的&#xff0c;用了Lottie动画和canvas标签做动画&#xff0c;登录和注册也连接了数据库。 图片是从网上找的&#xff0c;如有侵权私信我删除&#xff0c;谢谢啦~

洛谷 P2385 [USACO07FEB] Bronze Lilypad Pond B C语言 bfs

题目&#xff1a; https://www.luogu.com.cn/problem/P2385 题目看仔细&#xff0c;是M行N列.八个方向数组依靠M1,M2&#xff0c;所以初始化方向数组要在主函数里面&#xff0c;传入bfs函数里。 #include <iostream> #include<algorithm> #include<queue>…

如何在ubuntu上调试core dump

启用core dump 确认ulimit 状态 ulimit -c 如果输出是0&#xff0c;表示core dump被禁用了 运行 ulimit -c unlimited 再次运行 ulimit -c 确认输出是ulimited 设置core dump路径和文件名格式 下面命令表示设置core dump文件在当前目录&#xff08;%e表示程序名&#x…

告别照相馆!使用AI证件照工具HivisionIDPhotos打造在线证件照制作软件

文章目录 前言1. 安装Docker2. 本地部署HivisionIDPhotos3. 简单使用介绍4. 公网远程访问制作照片4.1 内网穿透工具安装4.2 创建远程连接公网地址 5. 配置固定公网地址 前言 本文主要介绍如何在Linux系统使用Docker快速部署一个AI证件照工具HivisionIDPhotos&#xff0c;并结合…