• 面试官:count(*)、count1(1)、count(主键)、count(字段) 哪个更快?

面试官:count(*)、count1(1)、count(主键)、count(字段) 哪个更快?

2025-08-16 12:33:07 栏目:宝塔面板 83 阅读

大家好,我是君哥。

使用 SQL 时,统计表数据量是经常遇到的需求,比如在商品页面展示商品库存量。

统计表数据量的方法有 count(*)、count1(1)、count(主键 id)、count(字段)。那这些统计方式哪个执行最快呢?以 MySQL 数据库为参考,今天来聊一聊这个话题。

count(*)

首先 ,count(*) 返回的是检索到的行数,无论数据行里是否包含空值。

如果使用的是 MyISAM 存储引擎,MyISAM 会把表的数据行数保存下来存到磁盘,因此执行 count(*) 的时候不用统计,而是直接把保存的结果查出来,效率最高。但这有几个前提条件:

  1. 不能带 where 条件;
  2. 只能从单表查询;
  3. 查询 SQL 不能有额外的字段;
  4. MyISAM 不支持事务,可能会有数据不一致的情况。

如果使用的是 InnoDB 存储引擎,count 就是一个聚合函数,对返回的结果集逐行进行判断,只要不是 NULL 就加 1,效率不如 MyISAM。当然,MySQL 对 count(*) 做了优化,会选择数据量最小的二级索引进行扫描,以提高执行效率。

count(1)

对于 count(1) 来说,InnoDB 引擎遍历整张表,server 层对于返回的每一行,不用取值,直接放一个数值 1 进去,然后计数值加 1。

count(主键 id)

对于 count(主键 id) ,InnoDB 引擎会遍历整张表,把每一行的 id 值取出来,返回给 server 层。server 层拿到 id 后,判断主键 id 不可能为空,计数值加 1。

count(字段)

对于 count(字段) 来说:如果字段定义成 not null,server 层逐行判断,只要引擎层返回的记录不为空,计数值加 1;如果这个字段定义成 null,那server 层拿到记录后,还需要取出值判断是不是 null,如果值不是 null,计数值加 1。

小结

对于 InnoDB 引擎来说,使用 count(*) 和 count(1) 是一样的,没有性能区别。下面是官网解释。

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

count(*) 比 count(主键 id) 快,因为执行 count(主键 id) 的时候,引擎层需要解析主键 id 的值返回给 server 层。

count(字段) 性能最差,因为引擎层解析字段值返回给 server 层后,server 层需要从行记录取出值进行判断是否为 NULL。

缓存

那有更快的方案查询表数据量吗?有。可以考虑使用 redis 缓存来。在 redis 中建 一个 key 来保存数据量,当表插入新数据时,缓存数据量 + 1。

但使用缓存可能会有两个问题:

  1. 会有数据不一致得情况,不适用于精确统计的场景;

比如上图,插入数据后,还没有来得及更新缓存,已经有应用查询了缓存的 count 值。

可以考虑把缓存的 count 值写入 MySQL 数据库,使用 InnoDB 引擎的事务来保证一致性。

2. redis 服务宕机后,会丢失数据。这个可以在 redis 重启后重新从数据库查询最新 count 数来写入缓存。

总结

  1. 如果数据量不大,比如不到百万级别,或者对 count 值精确度要求很高,可以直接使用 count(*) 获取行数。
  2. 如果数据量非常大,查询频率也很高,可以考虑缓存 count 值;
  3. 如果考虑使用缓存,但业务又要求 count 值精确,那就把 count 值缓存在数据库中;
  4. 如果对 count 精确度要求不高,可以考虑把 count 值缓存在 redis;
  5. 如果要统计某一个字段非空的行数,则使用 count(字段);
  6. 如果是分库分表的场景,则采用并行统计来提高效率。

本文地址:https://www.yitenyun.com/333.html

搜索文章

Tags

数据库 API FastAPI Calcite 电商系统 MySQL Web 应用 异步数据库 数据同步 ACK 双主架构 循环复制 TIME_WAIT 运维 负载均衡 服务器 管理口 JumpServer SSL 堡垒机 跳板机 HTTPS HexHub Docker 服务器性能 JumpServer安装 堡垒机安装 Linux安装JumpServer SQL 查询 Deepseek 宝塔面板 Linux宝塔 生命周期 esxi esxi6 root密码不对 无法登录 web无法登录 序列 核心机制 锁机制 Windows Windows server net3.5 .NET 安装出错 行业 趋势 HTTPS加密 Windows宝塔 Mysql重置密码 开源 PostgreSQL 存储引擎 宝塔面板打不开 宝塔面板无法访问 查看硬件 Linux查看硬件 Linux查看CPU Linux查看内存 机器学习 Redis Undo Log 机制 Oracle 处理机制 Spring 动态查询 无法访问宝塔面板 响应模型 优化 万能公式 InnoDB 数据库锁 异步化 连接控制 Serverless 无服务器 语言 监控 ES 协同 工具 group by 索引 openHalo Postgres OTel Iceberg 技术 高可用 缓存方案 缓存架构 缓存穿透 分页查询 scp Linux的scp怎么用 scp上传 scp下载 scp命令 存储 SVM Embedding GreatSQL 连接数 数据 主库 国产数据库 Linux 安全 R edis 线程 日志文件 MIXED 3 SQLite-Web SQLite 数据库管理工具 R2DBC 加密 场景 Netstat Linux 服务器 端口 OB 单机版 Recursive 启动故障 ​Redis 推荐模型 防火墙 黑客 云原生 RocketMQ 长轮询 配置 SQLark 自定义序列化 AI 助手 向量数据库 大模型 Canal 共享锁 PG DBA Hash 字段 信息化 智能运维 不宕机 Rsync Python 向量库 Milvus 磁盘架构 同城 双活 Ftp 分库 分表 电商 系统 业务 IT运维 语句 架构 修改DNS Centos7如何修改DNS 数据分类 聚簇 非聚簇 PostGIS 传统数据库 向量化 filelock 流量 频繁 Codis 线上 库存 预扣 MongoDB 数据结构 MVCC MCP 开放协议 缓存 失效 • 索引 • 数据库 redo log 重做日志 MySQL 9.3 mini-redis INCR指令 Web 接口 开发 数据类型 sftp 服务器 参数 人工智能 推荐系统 千万级 大表 ZODB 工具链 Doris SeaTunnel EasyExcel MySQL8 分布式架构 分布式锁​ Redisson 锁芯 聚簇索引 非聚簇索引 prometheus Alert INSERT 数据备份 高效统计 今天这篇文章就跟大家 主从复制 代理 窗口 函数 虚拟服务器 虚拟机 内存 事务 Java 容器 崖山 新版本 COMPACT 发件箱模式 SSH 引擎 性能 Web 网络架构 网络配置 分页 数据脱敏 加密算法 RDB AOF MGR 分布式集群 核心架构 订阅机制 网络故障 读写 速度 服务器中毒 Go 数据库迁移 自动重启 容器化 QPS 高并发 播客 B+Tree ID 字段 分布式 集中式 数据页 Redis 8.0 数据集成工具 Redka OAuth2 Token 微软 SQL Server AI功能 模型 SpringAI StarRocks 数据仓库 DBMS 管理系统 Entity 排行榜 排序 池化技术 连接池 Caffeine CP Valkey Valkey8.0 JOIN 关系数据库 事务隔离 原子性 业务场景 数据字典 兼容性 LRU Weaviate 网络 部署 Testcloud 云端自动化 dbt 数据转换工具 分页方案 排版 事务同步 Pottery 1 ReadView UUID ID 优化器 AIOPS sqlmock 日志 意向锁 记录锁 InfluxDB 悲观锁 乐观锁 单点故障 单线程 UUIDv7 主键 仪表盘 Pump 编程 Ansible 对象 Order Crash 代码 RAG HelixDB 分布式锁 Zookeeper 产业链 IT 字典 双引擎 恢复数据 订单 List 类型 LLM 拦截器 动态代理 国产 用户 线程安全 慢SQL优化 表空间 快照读 当前读 视图 count(*) count(主键) 行数 解锁 调优 RR 互联网 Next-Key GitHub Git 神经系统 矢量存储 数据库类型 AI代理 CAS 查询规划 技巧 算法 多线程 闪回 并发控制 恢复机制