首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >物联网平台MySQL:消息推送系统如何用分表方案解决百万用户广播难题

物联网平台MySQL:消息推送系统如何用分表方案解决百万用户广播难题

原创
作者头像
Yeats_Liao
发布2025-09-17 14:07:59
发布2025-09-17 14:07:59
2420
举报

物联网设备消息推送系统的数据库设计方案,专门解决海量设备通知的存储和查询问题。

1 数据库表结构设计

我们的物联网平台需要处理大量设备消息,包括设备告警、系统通知、固件升级提醒等。经过实际项目验证,采用4张表的分离设计最为合适。

1.1 设备用户表(device_users)

这张表存放所有注册用户的基本信息,可以直接复用现有的用户系统。

字段名

类型

说明

索引

id

BIGINT

用户编号

主键

username

VARCHAR(50)

登录账号

唯一索引

nickname

VARCHAR(50)

显示名称

create_time

DATETIME

注册时间

1.2 通知类型表(notification_types)

用来管理各种消息类型,比如设备告警、系统维护通知、固件更新等。

字段名

类型

说明

id

INT

类型编号(1=设备告警,2=私人消息,3=系统广播)

type_name

VARCHAR(50)

类型名称

1.3 消息内容表(notification_content)

这是核心表,存储所有消息的具体内容。不管是发给单个用户的告警,还是发给所有用户的系统通知,内容都只存一份。

字段名

类型

说明

索引

id

BIGINT

消息编号

主键

sender_id

BIGINT

发送者编号

普通索引

type_id

INT

消息类型

普通索引

title

VARCHAR(255)

消息标题

content

TEXT

消息内容

send_time

DATETIME

发送时间

普通索引

is_delete

BOOLEAN

是否删除

这样设计的好处很明显:一条系统广播消息只需要存储一次,不会因为有1万个用户就重复存储1万次。

1.4 用户消息关系表(user_notification_relation)

这张表记录每个用户收到了哪些消息,以及消息的读取状态。它把消息内容和用户接收状态完全分开管理。

字段名

类型

说明

索引

id

BIGINT

关系记录编号

主键

notification_id

BIGINT

消息编号

联合索引

user_id

BIGINT

用户编号

联合索引

is_read

BOOLEAN

是否已读

普通索引

read_time

DATETIME

阅读时间

is_delete

BOOLEAN

用户是否删除

create_time

DATETIME

记录创建时间

普通索引

每一行记录代表某个用户对某条消息的接收情况。比如一条系统广播发给1000个用户,就会产生1000条关系记录。

2 表之间的关联关系

代码语言:mermaid
复制
erDiagram
    device_users ||--o{ user_notification_relation : "接收"
    notification_content ||--o{ user_notification_relation : "关联"
    notification_types ||--o{ notification_content : "分类"

3 实际操作场景

3.1 发送设备告警消息

当某个温度传感器超过阈值时,系统需要通知设备管理员。

第一步,插入消息内容:

代码语言:sql
复制
INSERT INTO notification_content (sender_id, type_id, title, content, send_time)
VALUES (1, 1, '设备告警', '车间3号温度传感器温度过高', NOW());

第二步,为接收者创建关系记录:

代码语言:sql
复制
INSERT INTO user_notification_relation (notification_id, user_id, create_time)
VALUES (LAST_INSERT_ID(), 2, NOW());

3.2 发送系统广播通知

比如系统要维护,需要通知所有用户。这种场景下,我们用批量插入来处理。

先插入消息内容:

代码语言:sql
复制
INSERT INTO notification_content (sender_id, type_id, title, content, send_time)
VALUES (0, 3, '系统维护通知', '今晚22:00-24:00系统维护', NOW());

然后批量创建用户关系:

代码语言:sql
复制
INSERT INTO user_notification_relation (notification_id, user_id, create_time)
SELECT LAST_INSERT_ID(), id, NOW() FROM device_users;

这个操作很高效,假设有10万用户,一条SQL就能创建10万条关系记录。

3.3 查询用户的所有消息

用户登录后,需要看到自己的所有消息,包括已读和未读的。

代码语言:sql
复制
SELECT 
  nc.id AS notification_id,
  nc.title,
  nc.content,
  nc.send_time,
  unr.is_read,
  unr.read_time
FROM notification_content nc
JOIN user_notification_relation unr 
  ON nc.id = unr.notification_id
WHERE unr.user_id = 2
  AND nc.is_delete = false
  AND unr.is_delete = false
ORDER BY nc.send_time DESC;

4 这套方案的优点

4.1 节省存储空间

消息内容只存一份,通过关系表来管理用户状态。一条发给1万人的通知,数据库里只有1条内容记录 + 1万条关系记录,而不是1万条完整的消息记录。

4.2 批量操作性能好

系统广播通过 INSERT ... SELECT 批量生成关系记录,比一条条插入快很多。实测中,给10万用户发广播,批量插入比循环插入快15倍。

4.3 扩展性强

想加新的消息类型?只需要在 notification_types 表里加一行。

想给消息加新状态?在 user_notification_relation 表里加字段就行。

4.4 查询灵活

可以轻松实现各种查询需求:

  • 查未读消息数量
  • 按消息类型分组统计
  • 查询某个时间段的消息
  • 查询某类设备的告警消息

5 性能优化建议

5.1 索引策略

user_notification_relation 表上创建 (user_id, is_read, create_time) 联合索引,这样查询未读消息会很快。

notification_content 表的 send_time 字段上加索引,按时间排序查询会更快。

5.2 分表策略

如果用户量超过百万,可以考虑按 user_id 哈希分表存储 user_notification_relation。比如用户ID末位是0-4的放在表A,5-9的放在表B。

5.3 避免重复数据

user_notification_relation 表的 (notification_id, user_id) 加唯一约束,防止同一条消息给同一个用户创建多条关系记录。

这套分表方案在我们的物联网项目中运行了2年多,处理过单次10万+用户的系统广播,查询响应时间稳定在100ms以内。既保证了灵活性,又解决了大批量消息推送的性能问题。

代码语言:sql
复制
-- 创建设备用户表
-- 存储物联网平台的用户基础信息
CREATE TABLE device_users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '用户编号,系统内唯一标识',
    username VARCHAR(50) NOT NULL UNIQUE COMMENT '登录账号,用户登录时使用',
    nickname VARCHAR(50) COMMENT '用户昵称,界面显示用',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '注册时间'
);

-- 创建通知类型表
-- 管理物联网平台中的各种消息类型
CREATE TABLE notification_types (
    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '类型编号',
    type_name VARCHAR(50) NOT NULL UNIQUE COMMENT '类型名称,如设备告警、系统通知等'
);

-- 创建消息内容表
-- 存储所有消息的具体内容,不区分接收者
CREATE TABLE notification_content (
    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '消息编号,全局唯一',
    sender_id BIGINT NOT NULL COMMENT '发送者编号,关联用户表',
    type_id INT NOT NULL COMMENT '消息类型编号',
    title VARCHAR(255) NOT NULL COMMENT '消息标题',
    content TEXT NOT NULL COMMENT '消息具体内容',
    send_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '发送时间',
    is_delete BOOLEAN DEFAULT false COMMENT '是否删除标记',
    INDEX idx_sender_id (sender_id) COMMENT '发送者索引,提高按发送者查询效率',
    INDEX idx_type_id (type_id) COMMENT '消息类型索引',
    INDEX idx_send_time (send_time) COMMENT '发送时间索引,用于时间排序',
    FOREIGN KEY (type_id) REFERENCES notification_types(id)
);

-- 创建用户消息关系表
-- 记录每个用户收到的消息及其状态
CREATE TABLE user_notification_relation (
    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '关系记录编号',
    notification_id BIGINT NOT NULL COMMENT '消息编号',
    user_id BIGINT NOT NULL COMMENT '接收用户编号',
    is_read BOOLEAN DEFAULT false COMMENT '是否已读,默认未读',
    read_time DATETIME COMMENT '阅读时间,用户点击查看时记录',
    is_delete BOOLEAN DEFAULT false COMMENT '用户是否删除此消息',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '关系创建时间',
    INDEX idx_notification_user (notification_id, user_id) COMMENT '消息用户联合索引',
    INDEX idx_is_read (is_read) COMMENT '已读状态索引,快速查询未读消息',
    INDEX idx_create_time (create_time) COMMENT '创建时间索引',
    FOREIGN KEY (notification_id) REFERENCES notification_content(id),
    FOREIGN KEY (user_id) REFERENCES device_users(id)
);    

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 数据库表结构设计
    • 1.1 设备用户表(device_users)
    • 1.2 通知类型表(notification_types)
    • 1.3 消息内容表(notification_content)
    • 1.4 用户消息关系表(user_notification_relation)
  • 2 表之间的关联关系
  • 3 实际操作场景
    • 3.1 发送设备告警消息
    • 3.2 发送系统广播通知
    • 3.3 查询用户的所有消息
  • 4 这套方案的优点
    • 4.1 节省存储空间
    • 4.2 批量操作性能好
    • 4.3 扩展性强
    • 4.4 查询灵活
  • 5 性能优化建议
    • 5.1 索引策略
    • 5.2 分表策略
    • 5.3 避免重复数据
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档