如何提升MySQL千万级大表Count(*)查询效率?借助Redis或元数据表实现实时统计?
- 内容介绍
- 文章标签
- 相关推荐
本文共计870个文字,预计阅读时间需要4分钟。
由于InnoDB引擎下默认使用COUNT(*)走全表扫描(即使有主键),不进行二级索引优化,也无法利用查询缓存(MySQL 8.0已移除),当表行数超过1000万、QPS较高时,单次COUNT(*)操作可能耗时2-5秒,甚至更容易阻塞其他DML操作。
用 Redis 做实时计数的实操要点
适合写多读少、允许短暂误差(秒级)的场景,比如「当前在线用户数」「文章总浏览量」。关键不是存总数,而是控制好增减时机和原子性。
-
INCRBY和DECRBY必须和业务 SQL 在同一事务中触发 —— 但 Redis 本身不参与 MySQL 事务,所以实际要靠应用层双写 + 补偿:先更新 MySQL,再INCRBY;失败则记录日志,由后台任务重试 - 不要用
GET+SET模拟原子增减,会丢数据;必须用INCRBY - 为防 Redis 宕机导致计数丢失,建议每天凌晨用
SELECT COUNT(*) FROM t全量校准一次,写入SET t:count:backup作为兜底值 - 如果业务有「软删除」,记得在删除逻辑里同步
DECRBY 1;硬删除则通常已含该逻辑
用元数据表替代 COUNT(*) 的落地方式
比 Redis 更可靠,适合要求强一致的场景,比如「会员总人数」「待审核订单数」。本质是把聚合结果物化成一行一列的普通表。
本文共计870个文字,预计阅读时间需要4分钟。
由于InnoDB引擎下默认使用COUNT(*)走全表扫描(即使有主键),不进行二级索引优化,也无法利用查询缓存(MySQL 8.0已移除),当表行数超过1000万、QPS较高时,单次COUNT(*)操作可能耗时2-5秒,甚至更容易阻塞其他DML操作。
用 Redis 做实时计数的实操要点
适合写多读少、允许短暂误差(秒级)的场景,比如「当前在线用户数」「文章总浏览量」。关键不是存总数,而是控制好增减时机和原子性。
-
INCRBY和DECRBY必须和业务 SQL 在同一事务中触发 —— 但 Redis 本身不参与 MySQL 事务,所以实际要靠应用层双写 + 补偿:先更新 MySQL,再INCRBY;失败则记录日志,由后台任务重试 - 不要用
GET+SET模拟原子增减,会丢数据;必须用INCRBY - 为防 Redis 宕机导致计数丢失,建议每天凌晨用
SELECT COUNT(*) FROM t全量校准一次,写入SET t:count:backup作为兜底值 - 如果业务有「软删除」,记得在删除逻辑里同步
DECRBY 1;硬删除则通常已含该逻辑
用元数据表替代 COUNT(*) 的落地方式
比 Redis 更可靠,适合要求强一致的场景,比如「会员总人数」「待审核订单数」。本质是把聚合结果物化成一行一列的普通表。

