后台首页显示订单总数,count(*) 跑 4.2 秒,表里 800 万行。explain 显示走的是 idx_status,rows 估算 800 万。第一次遇到会往复杂处想,其实漏掉的多是个小前提。

EXPLAIN SELECT COUNT(*) FROM orders;
SELECT table_rows FROM information_schema.tables
WHERE table_name = 'orders';

InnoDB 不保存精确行数,count(*) 要挑一棵最小的索引从头扫到尾,扫完才知道结果。二级索引比聚簇索引窄,优化器会优先选它,代价仍然是整棵索引扫描。这一点先确认清楚,后面就不用反复试。

「count 统计慢」这类改动最怕改一半,回滚脚本先准备好,再动生产。临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。

动手前把原文件复制一份带时间戳,出问题立刻换回去,比现场分析快得多。

具体做法是,确认 count 是否真需要精确值 展示场景可以用估算或者缓存;需要精确值就单独维护计数表 写入时加减;把统计做成定时任务 结果放缓存 页面直接读;实在要现算 就固定走最小的那个二级索引。

改完照着核一遍,首页统计接口从 4 秒降到毫秒级 数字和 count(*) 的偏差在可接受范围内。

作者 9823189