直接回答:InnoDB 对 count() 没有捷径,必须扫描全表(实际是最小的那棵索引树)并逐行判断可见性——MVCC 下每行对当前事务是否可见只有执行时才知道,所以无法像 MyISAM 那样把行数直接存起来。亿级表单次 count() 要几十秒甚至更久。
展开解析:常用替代方案按精度分层:一,近似值用 EXPLAIN 的 rows 或 information_schema.TABLES 的 TABLE_ROWS,来自采样统计,误差可能 40% 以上,够用于“约多少条”的展示;二,汇总表计数,insert/delete 在同一事务里维护一张 counter 表,读取 O(1),代价是计数行的写锁竞争,可分桶成多行再求和缓解;三,Redis 计数器,快但要处理缓存与库的一致性以及 Redis 丢数据后的重建;四,离线统计,数仓或定时任务异步算好写入结果表。工程细节上,count() 会自动选择最小的二级索引扫描,所以保证存在合适的窄索引也能明显提速;MySQL 8.0 的并行扫描(innodb_parallel_read_threads)对全量 count 也有帮助。带 WHERE 条件的计数只能走索引加扫描,可考虑覆盖索引或按维度预聚合。另外注意 MyISAM 的 O(1) 行数只对无 WHERE 的 count() 成立,加上条件一样要扫表。
追问方向:为什么 count(*) 的结果不能直接缓存?计数表方案如何处理并发下的一致性?分页接口“总数+列表”该如何设计? (约 359 字)