Sunday面试指南

MySQL 的 COUNT(*)、COUNT(1)、COUNT(字段) 有什么区别?

🧑‍💻 面试官:COUNT(*)、COUNT(1)、COUNT(字段),哪个最快?

🙋‍♂️ 我:COUNT(1) 不读取整行,所以最快。

🧑‍💻 面试官:COUNT(*) 真会把所有列的值都取出来吗?

🙋‍♂️ 我:那它应该只是计数。

🧑‍💻 面试官:如果字段里有 NULL,结果还一样吗?先别比速度,你准备统计什么?

先定义计数对象:数行,还是数某个表达式的非 NULL 值。对象不一样,讨论“哪个更快”就已经跑题了。

面试速答(60 秒版)

COUNT() 数查询结果的行数,不管这一行里有没有 NULL。COUNT(1) 对每行的非空常量 1 计数,因此结果和 COUNT() 一样;在 InnoDB 中,不应宣称它天然更快。

COUNT(字段) 数的是这个字段非 NULL 的行。如果字段有空值,它和数全部行就不是同一个问题。COUNT(DISTINCT 字段) 还会去重,并排除 NULL。

InnoDB 不能用一个全局精确行数回答所有事务,因为不同事务可见的数据可能不同。全表精确计数仍需要访问相应记录或索引。

优化时要看过滤条件、索引、可见性和统计频率。允许近似就用近似统计;需要精确业务数,则单独设计计数的一致性,不能靠换一个 COUNT 写法解决。

三行数据中包含一个 NULL,行计数为三,负责人非空值计数为二

知识点详解:计数函数先决定“这一项算不算”

三条数据,足够看清差别

假设任务表有三条记录,负责人分别是小张、小李、NULL。对于这三条结果:

写法结果数的是什么
COUNT(*)3三行
COUNT(1)3每行一个非 NULL 的常量
COUNT(owner)2两个非 NULL 负责人
COUNT(NULL)0没有非 NULL 项

空字符串不是 NULL。如果字段值是空字符串,它仍然会被 COUNT(字段) 计入。先明确缺失值怎么保存,计数才有业务意义。

星号不等于读取整行所有列

SELECT * 取多列,COUNT(*) 的星号不是同样的操作。后者表达的是行计数,并不要求把所有列的值输出或逐个拼成完整结果。

对于常规 InnoDB 计数,官方说明 COUNT(*) 和 COUNT(1) 处理方式相同,不存在靠把星号换成 1 就天然加速的结论。

如果测试出来某次差一点,还要排除缓存、并发、执行计划和测量波动,不能把一次耗时写成通用性能排名。

事务不同,看到的总数可能不同

例如事务 A 已经建立一个一致性读视图,随后事务 B 新增并提交一条任务。A 在它的读取规则下,可能继续看到原来的数量;新事务则能看到新增记录。

因此 InnoDB 没法维护一个精确全局数,让所有事务都不检查可见性就得到正确答案。无过滤的 COUNT(*) 通常选择较小的二级索引扫描,没有二级索引则需要扫描聚簇索引;具体查询仍以计划为准。

加 WHERE 后,还要把筛选范围和索引匹配考虑进去。计数不是免费的元数据查询。

LEFT JOIN 后,COUNT(*) 还可能多算

想统计每位用户的登录次数时,没有登录的用户也会被 LEFT JOIN 补出一行。COUNT(*) 会数这行,于是零次被算成一次。

计数右表的非空登录主键,才会在这份 NULL 补行上得到零。这里不是“字段计数更快”,而是字段计数符合目标。

频繁统计大表时,可以讨论缓存、异步聚合或事务内计数器。但每种方案都有更新时间、热点竞争和修复成本,先说明允许误差,才好选择。

本题机制参考:聚合函数、一致性非锁定读、EXPLAIN 输出。

面试官继续追问

COUNT(DISTINCT owner) 会数 NULL 吗?

不会,单表达式时统计不同的非 NULL 值。两条相同负责人只计一次。

统计总数一定要扫表吗?

精确 InnoDB 计数需要处理当前事务可见记录,但可以利用索引,不等于总是读取整行。MyISAM 的特定元数据优化不能套到 InnoDB。

表状态里的 Rows 能直接用吗?

可以用于允许误差的估计场景,不能当作任意条件和事务视图下的精确业务总数。

面试速记卡

  • COUNT(*):数结果行,包含有 NULL 的行。
  • COUNT(1):非空常量计数,不天然比星号快。
  • COUNT(列):数非 NULL 值,空字符串仍计数。
  • DISTINCT:去重后计数,不计 NULL。
  • InnoDB:精确计数受事务可见性与访问量影响。

公司面试真题

这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。

浏览公司面试真题 →
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历