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

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

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

大家好,我是君哥。

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