mysql如何设计消息通知表_mysql系统项目示例

来源:这里教程网 时间:2026-02-28 20:37:14 作者:

消息通知表需要存哪些核心字段

通知表不是日志表,不能只记“谁发了什么”。必须支持未读/已读状态、用户粒度的分发、点击跳转、批量标记,否则后期查 unread_count 或做推送补发会极其痛苦。

关键字段包括:

id
user_id
(接收者,非 sender_id)、
type
(如
"order_paid"
"system_announce"
)、
content
(建议 JSON 格式存结构化内容,而非纯文本)、
link
(跳转路径,如
"/orders/123"
)、
is_read
(TINYINT(1),0/1)、
created_at
expires_at
(可选,避免垃圾数据堆积)。

不推荐把

sender_id
或业务主键(如
order_id
)直接当外键硬关联——业务表可能删记录,但通知要长期保留。可用
ref_type
+
ref_id
组合泛化引用,例如:
ref_type = "order"
ref_id = "123"

索引怎么建才不拖慢查询

高频查询是「查某用户未读数」和「拉取最新 20 条」,这两类查询必须走索引,否则

SELECT COUNT(*) FROM notify WHERE user_id = 123 AND is_read = 0
在百万级数据下会秒变慢 SQL。

ALTER TABLE `notify` ADD INDEX `idx_user_read` (`user_id`, `is_read`, `created_at`);

这个联合索引覆盖了三个常用过滤条件,且

created_at
放最后可支持
ORDER BY created_at DESC LIMIT 20
无需 filesort。

注意:别单独给

is_read
建索引——区分度太低(95% 是 0),MySQL 优化器大概率不走;也别漏掉
user_id
,它是查询的绝对前置条件。

如何避免重复插入相同通知

比如订单支付成功后,下游服务可能因重试触发多次通知逻辑,导致用户收到 3 条一模一样的「付款成功」提醒。

解决方法是加唯一约束:

UNIQUE KEY `uk_user_type_ref` (`user_id`, `type`, `ref_id`)
。前提是业务上允许「同一用户对同一业务实体只收一条同类通知」——这在大多数场景成立(比如你不会想看到 5 条「你的订单 #123 已发货」)。

插入时用

INSERT IGNORE
ON DUPLICATE KEY UPDATE is_read = VALUES(is_read)
,避免报错中断流程。

如果类型逻辑更复杂(如「7 天内只推一次优惠券」),就得在应用层用 Redis 记录

user:123:type:coupon:seen
并设 TTL,数据库层无法优雅解决时间窗口去重。

要不要分表?什么时候开始拆

单表撑到 500 万行以内,只要索引合理、归档策略到位,完全不用分表。过早分片只会增加 join、count、后台管理的复杂度。

真正该拆的信号是:

SHOW PROCESSLIST
里频繁出现
Copying to tmp table
Creating sort index
;或者每天新增超 10 万条,且
is_read = 0
的比例长期低于 5%,说明冷数据太多。

优先考虑按时间归档:每月建一个

notify_202406
表,用视图或应用路由写入;比按 user_id hash 分片更易维护、更利于物理删除旧数据。

另外,

content
字段如果平均超 2KB,建议抽到单独的
notify_payload
表,主表只留摘要,避免主索引膨胀拖慢所有查询。

相关推荐