当前位置: 代码网 > it编程>数据库>Mysql > 深入剖析MySQL中COUNT(id)和COUNT(*)哪个效率更高

深入剖析MySQL中COUNT(id)和COUNT(*)哪个效率更高

2026年07月26日 Mysql 我要评论
前言开发工作中统计行数,经常会写出两种写法:select count(*) from `user_login_log` where `date` = curdate();select count(id

前言

开发工作中统计行数,经常会写出两种写法:

select count(*) from `user_login_log` where `date` = curdate();
select count(id) from `user_login_log` where `date` = curdate();

网上充斥大量老旧传言:count(*) 需要扫描整行数据,count(id) 只读取主键,count(id) 速度更快。

这条说法放到现在 innodb 引擎下是错误谣言

本文结合 innodb 底层原理,讲清楚 count(*)count(id)count(普通字段) 的差异,给出生产环境标准编码规范。

前置环境:本文全部基于 mysql innodb(5.7 / 8.0,线上最通用);myisam 机制不一样,文末单独说明。

一、先搞懂三个count语法的语义

1. count(*)

sql标准定义:统计满足查询条件的所有行数,不做任何 null 判断。

mysql官方专门对 count(*) 做优化,优化器会选择当前表体积最小的二级索引进行扫描计数,不需要读取聚簇索引完整行数据。

2. count(id)

语义:统计 id is not null 的记录行数。

一般业务中 id 为主键,主键字段强制非空,所以逻辑等价统计总行数。

执行逻辑:扫描索引,读取主键id的值,判断不为null后计数。

3. count(普通业务字段)

count(login_ip)

语义:统计 login_ip is not null 的记录。

风险两点:

  1. 如果字段允许null,统计结果和真实行数不一致,产生业务bug;
  2. innodb需要取出字段真实值判断null,开销高于 count(*)。

二、核心结论(innodb)

带where条件统计时,count(*) 和 count(id) 性能几乎没有差距。

不要耗费精力纠结二者选择,二者执行计划、扫描行数、io开销基本持平。

底层原因:innodb二级索引叶子节点本身就存放主键id。

无论优化器选择二级索引扫描计数:

  • count(*):只需要计数索引条目,不需要读取字段值
  • count(id):除了计数,还要额外取出id值做非空判断

理论上 count(*)略微优于 count(id),只是绝大多数场景差距感知不到。

三、误区拆解:为什么会流传 count(id) 更快?

谣言来源大多是老旧myisam认知混淆,以及早期网络文章以讹传讹:

  1. myisam无where条件 count(*) 超快,引擎缓存总行数;但myisam早已不是主流;
  2. 很多人主观猜想:* 代表读取整行数据,实际上mysql优化器根本不会读取完整行;
  3. 没有区分「有无where条件」,笼统下定论。

重点纠正:innodb中,count(*) 不会读取完整一行数据,优化器只利用索引条目数量统计。

四、无where条件的特殊场景

-- 查询整张表总条数
select count(*) from `user`;
select count(id) from `user`;

很多人发现这条sql查询很慢。

原因:innodb事务多版本机制,没有办法缓存表总行数,无论 count(*) / count(id) 都必须扫描索引统计,二者速度依旧基本一致。

想要高频查询表总量提速:使用redis缓存、定时统计表总数,避免频繁count扫描索引。

五、新增对比:count(常量)

额外拓展一个写法:

select count(1) from `user_login_log` where `date` = curdate();

在新版本mysql中,count(1) 会被优化器等价优化成 count(*),性能同样持平。

不用盲目推崇count(1)。

六、一张表清晰区分三种写法

写法作用是否判null性能建议风险
count(*)统计所有符合条件行不判断null✅推荐,官方标准
count(id)统计id不为null的行判断null可用,略逊于count(*)id必须为主键非空,否则结果异常
count(login_ip)统计login_ip不为null的行判断null❌不推荐字段存在null时统计数量失真,开销更大

七、线上编码规范建议

优先使用 count(*),遵循sql标准,语义清晰,mysql官方推荐;

-- 标准写法
select count(*) as active_num from user_login_log where `date` = curdate();

禁止使用 count(普通业务字段) 统计表总行数;

如果需要统计「某字段不为空」的数据,才使用 count(字段名)

-- 合理场景:统计有登录ip的用户
select count(login_ip) from user_login_log where `date` = curdate();

不要为了“优化性能”把 count(*) 强行改成 count(id),属于无效优化;

大表频繁全量count统计,使用缓存预聚合方案。

八、实战验证方式

使用explain对比两条sql执行计划:

explain select count(*) from user_login_log where `date` = curdate();
explain select count(id) from user_login_log where `date` = curdate();

观察输出:type、key、rows基本完全一致,可以直观证明性能差距极小。

九、补充:myisam简要区分(了解即可)

myisam引擎内部保存表总行数:

select count(*) from `user`; -- 不加where,瞬间返回

但只要带上where条件,myisam同样需要扫描数据,此时 count(*)count(id) 同样差距不大。

新项目基本不会使用myisam,仅作知识拓展。

十、全文总结

  1. innodb引擎下,count(*)count(id) 性能几乎持平,count(*) 理论小幅领先;
  2. 网传「count(id)速度更快」属于过时谣言,不要作为优化依据;
  3. 统计满足条件全部行数,统一使用 count(*)
  4. 杜绝用 count(普通字段) 统计总行数,存在逻辑bug与性能损耗;
  5. sql优化把重心放在索引设计,不要在count写法上做无效内卷。

写代码记住一条准则:先保证语义准确,再追求性能;符合sql标准的 count(*) 是兼顾可读性与性能的最优选择。

以上就是深入剖析mysql中count(id)和count(*)哪个效率更高的详细内容,更多关于mysql count(id)和count(*)对比的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com