未读数量优化

未读数为什么难

老王问:「未读数量查询会不会很慢?」

数据量:

insite_messages 表:
- 总消息数:500 万条
- 每用户平均:100 条
- 每用户未读:10 条

未读数量查询是高频操作,每次打开 App 都要查。如果每次都 COUNT(*) WHERE is_read = 0,会在大表上反复全扫。

方案 A:Redis 缓存

  • 未读数存 Redis,读取快。
  • 问题:缓存过期 / 不一致时数字不准,需要兜底。

方案 B:独立计数表

新建 user_unread_counts:

字段含义
user_id用户
type通知类型
count未读数

每次创建 / 标记已读时,更新计数:

创建消息:INSERT 消息 + UPDATE 计数 +1
标记已读:UPDATE 消息 + UPDATE 计数 -1

未读计数的更新流程

业务事件(新评论 / 点赞)

写入消息 + 计数 +1(同一事务)

步骤 1 · 动作保证一致性

打开 App 读取计数表

步骤 2 · 动作毫秒级,不 COUNT 大表

标记已读 + 计数 -1

步骤 3 · 动作同步给其他设备

定期对账

步骤 4 · 判断纠正常见偏差
未读数准确、读取快

为什么选方案 B

我选择了独立计数表,因为:

  1. 计数准确:不依赖缓存过期。
  2. 按类型统计:可分别统计评论未读 3 条、点赞未读 5 条。
  3. 性能好:更新时只需一条 SQL。

计数一致性的注意点

  • 消息创建与计数更新要在同一事务,避免不一致。
  • 定期对账:扫描 is_read 与计数表,纠正常见的偏差。
  • 类型维度:计数的粒度和业务查询一致。

一句话

未读数优化 = 独立计数表 + 事务一致性 + 定期对账。用「预聚合的计数」替代「每次 COUNT」,是高频查询的标准解法。

发现内容有问题?

告诉我们哪里需要改进。