3. 报警数据模型设计
报警管理系统的可靠性,很大程度上取决于数据模型是否把“谁在什么设备上、按什么规则、在什么时间、以什么状态触发了什么报警”表达清楚。如果模型只设计一张“报警记录表”,把设备名称、规则阈值、处理人全部塞进同一行,短期能跑,长期必然出现数据冗余、状态不一致和统计口径混乱。本节围绕四个核心实体——设备、报警规则、报警记录、处理状态——完成概念模型到物理表结构的落地。
一、先厘清实体边界与主键策略
设备(device)是报警产生的物理载体,例如“杀菌釜 ST-01”“冷库压缩机 CP-03”。设备表保存设备编号、名称、类型、所属车间、安装位置和运行状态。主键建议使用自增整型 id,同时为业务编号 device_code 建唯一索引,避免业务人员改编号时牵连历史报警。
报警规则(alarm_rule)描述“什么条件算报警”。一条规则绑定一台设备(也可扩展为绑定设备类型),包含监测参数(如温度、压力、液位)、比较方式(大于、小于、区间外)、阈值、持续时间、报警等级和是否启用。规则与设备是多对一关系:一台设备可以配置多条规则,例如杀菌釜同时配置“温度超上限”和“压力超上限”。
报警记录(alarm_record)是规则被触发后产生的事实数据,属于典型的“事件型”实体,只追加、不随意修改。它记录触发时间、触发值、规则快照(阈值、等级)、关联设备和规则、当前处理状态。这里有一个关键设计决策:报警记录中应冗余保存触发时的阈值和等级,而不是每次查询都回查规则表。因为规则阈值后续可能被调整,历史报警必须保留“当时按什么标准判定的”,否则追溯会失真。
处理状态有两种建模方式:一是直接在报警记录表放一个 status 字段(如 0 未处理、1 处理中、2 已关闭、3 误报);二是独立建 alarm_handle 处理流水表,记录每次确认、派工、关闭的操作人、时间和备注。工程上推荐“状态字段 + 处理流水表”组合:状态字段用于快速筛选和看板统计,流水表用于审计追溯。若系统规模较小,也可只保留状态字段并附加 handler_id、handled_at、handle_remark 三个字段,但会丢失多次处理的过程记录。
二、关系与约束:把业务规则写进数据库
从ER图可以看到三条主要关系:设备与规则是一对多,规则与报警记录是一对多,报警记录与处理流水是一对多。报警记录同时引用设备和规则,其中 device_id 用于按设备维度统计,rule_id 用于追溯判定依据。为避免规则被删除后历史报警失去来源,规则表建议采用逻辑删除(is_deleted),外键使用 ON DELETE RESTRICT。
几个容易被忽略的约束值得提前定义:报警记录的 trigger_time 与 device_id 建联合索引,支撑“某设备最近24小时报警”这类高频查询;status 用 TINYINT 并在应用层枚举,避免中文字符串直接入库;trigger_value 与 snapshot_threshold 使用 DECIMAL(10,2),不要用 FLOAT,防止阈值比较出现浮点误差。此外可加唯一约束 UK(rule_id, trigger_time) 防止采集端重复上报造成同一条报警重复入库。
三、物理表结构示例
以下给出核心表的建表语句(MySQL 语法,示例参数可按实际调整):
CREATE TABLE device (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
device_code VARCHAR(32) NOT NULL,
device_name VARCHAR(64) NOT NULL,
device_type VARCHAR(32) NOT NULL,
workshop VARCHAR(64),
location VARCHAR(128),
run_status TINYINT DEFAULT 1, -- 1运行 0停机
UNIQUE KEY uk_code (device_code)
);
CREATE TABLE alarm_rule (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
device_id BIGINT NOT NULL,
param_name VARCHAR(32) NOT NULL, -- temperature / pressure
compare_op VARCHAR(8) NOT NULL, -- GT / LT / OUT
threshold DECIMAL(10,2) NOT NULL,
duration_s INT DEFAULT 0, -- 持续超限秒数
alarm_level TINYINT NOT NULL, -- 1提示 2警告 3严重
is_enabled TINYINT DEFAULT 1,
is_deleted TINYINT DEFAULT 0,
UNIQUE KEY uk_dev_param (device_id, param_name),
CONSTRAINT fk_rule_dev FOREIGN KEY (device_id)
REFERENCES device(id) ON DELETE RESTRICT
);
CREATE TABLE alarm_record (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
device_id BIGINT NOT NULL,
rule_id BIGINT NOT NULL,
trigger_time DATETIME NOT NULL,
trigger_value DECIMAL(10,2) NOT NULL,
snapshot_threshold DECIMAL(10,2) NOT NULL,
alarm_level TINYINT NOT NULL,
status TINYINT DEFAULT 0, -- 0未处理 1处理中 2已关闭 3误报
handler_id BIGINT,
handled_at DATETIME,
recover_time DATETIME,
KEY idx_dev_time (device_id, trigger_time),
UNIQUE KEY uk_rule_time (rule_id, trigger_time)
);
四、状态流转与设计校验
处理状态不是随意赋值的字段,而应遵循明确流转:新报警写入时 status=0;操作员确认后置为 1 并写入 handler_id、handled_at;故障排除或误报判定后置为 2 或 3,同时写入 recover_time。每次状态变更都向 alarm_handle 追加一条流水,保证“谁在何时做了什么”可审计。需要强调的是,状态只能单向推进,已关闭的报警不允许回退为未处理,否则统计报表会出现重复计数。
设计完成后可用三个问题自检:第一,任意一条历史报警能否还原出触发时的设备、规则阈值和等级?第二,按设备、按等级、按时间段统计报警数量时,是否需要跨表关联大表?第三,规则阈值调整后,旧报警的判定依据是否仍然准确?若三个答案都令人满意,说明模型基本可用。实际开发中还应预留 ext_json 之类的扩展字段,用于存放不同设备类型的个性化信息,避免频繁改表。