设备管理系统数据库设计实战:设备台账、设备树 BOM 与保养计划的 ER 建模

引言:模型错一点,业务歪一片

设备运维系统的数据库设计,最怕的不是复杂,而是**"当时看着没问题"**。

我们第一个版本的设备表是个 60 多列的大宽表,塞满了所有想得到的字段。三个月后客户说"不同型号的空压机参数不一样",我们开始加列;又过了两个月客户说"我想给设备挂自定义参数",宽表彻底崩溃。重建数据模型花了我们六周,迁移历史数据时每一个夜晚都在祈祷。

这篇把重建后的模型完整讲一遍:设备台账、设备树/BOM、保养计划三块核心建模,附 DDL。设计决策全部附上"为什么",你可以不同意结论,但决策路径可以复用。

一、设备台账:静态属性与动态属性分离

设备信息天然分两类:

  • 静态属性:名称、型号、厂商、出厂编号、安装位置、投运日期------低频变更,强结构;
  • 动态属性:运行时长、累计产量、当前状态、健康分------高频变化,来源多样。

而静态属性内部还有一个隐藏坑:不同设备型号的关键参数完全不同(空压机有排气量,电梯有载重,水泵有扬程)。三种方案对比:

方案 优点 致命缺点
大宽表 查询简单 每接一个新品类就加列,表结构爆炸
EAV(行转属性) 灵活 查询要多次自连接,索引难做
固定列 + JSON 动态列 常用字段可索引,长尾字段灵活 JSON 字段无强约束

我们选了第三种:高频筛选的属性固化为列(设备类型、品牌、位置、状态),型号特有参数进 JSON 列,MySQL 8.0 的 JSON 函数 + 虚拟列索引兜住了查询需求:

sql 复制代码
CREATE TABLE device (
    id            BIGINT PRIMARY KEY AUTO_INCREMENT,
    tenant_id     BIGINT NOT NULL,
    device_code   VARCHAR(64) NOT NULL COMMENT '设备编码,租户内唯一',
    device_name   VARCHAR(128) NOT NULL,
    device_type   VARCHAR(32)  NOT NULL COMMENT '型号ID,关联device_type表',
    dept_id       BIGINT       NOT NULL COMMENT '所属组织(数据权限用)',
    location_path VARCHAR(128) NOT NULL COMMENT '设备树路径 /1/23/456/',
    status        TINYINT      NOT NULL DEFAULT 1 COMMENT '1在用2停用3报废',
    commission_at DATE COMMENT '投运日期',
    attrs         JSON COMMENT '型号特有参数 {"exhaust_m3_min":12.5}',
    version       INT NOT NULL DEFAULT 0,
    UNIQUE KEY uk_tenant_code (tenant_id, device_code),
    KEY idx_location (location_path),
    KEY idx_type_status (device_type, status),
    generated_col: exhaust_m3_min DECIMAL(10,2)
        GENERATED ALWAYS AS (attrs->>'$.exhaust_m3_min') VIRTUAL  -- 示意
) COMMENT '设备台账';

设备类型表(device_type)里定义 JSON Schema 约束 + 默认点表/保养模板,新设备品类接入 = 建一个类型记录,不改表。这是当初重建模型最值的一个决定。

二、设备树:邻接表 + 路径字段的双写

设备组织结构是标准的树:厂区 → 车间 → 产线 → 设备,深 4~6 级,节点几千个。邻接表(parent_id)写起来最自然,但"查某车间下所有设备(含子产线)"需要递归------第一版的递归 SQL 在树深 6 级时性能惨不忍睹(第二篇踩坑里提过)。

重建后的方案:邻接表保关系,location_path 保查询

sql 复制代码
CREATE TABLE device_node (
    id         BIGINT PRIMARY KEY,
    parent_id  BIGINT,
    node_type  TINYINT NOT NULL COMMENT '1厂区2车间3产线4设备',
    name       VARCHAR(128) NOT NULL,
    path       VARCHAR(128) NOT NULL COMMENT '物化路径,如 /1/23/456/',
    depth      INT NOT NULL,
    KEY idx_path (path)
);

核心查询对比:

sql 复制代码
-- 查 456 节点整棵子树(含自身):一次前缀匹配,毫秒级
SELECT * FROM device_node WHERE path LIKE '/1/23/456%';
-- 查任意节点的祖先链:解析 path 字符串,按 / 拆 ID 后 IN 查询
SELECT * FROM device_node WHERE id IN (1, 23, 456);

双写的一致性靠子树整体重写 :移动一个节点时,把它及全部子孙的 path 前缀批量替换(UPDATE ... SET path = REPLACE(path, '/1/23/', '/1/99/') WHERE path LIKE '/1/23/%')。设备移动是低频操作,重写代价完全可接受。另外注意 LIKE '/1/23/456%' 的前缀陷阱:456 会匹配到 4567,所以路径段必须带尾分隔符(/1/23/456/),匹配 '/1/23/456/%'

BOM(部件构成)是另一棵树,但我们没有让它复用设备树 :设备树是管理视角的组织结构(会按客户组织调整),BOM 是物理视角的构成关系(跟着设备型号走),两者生命周期不同。device_part 表带 device_id + parent_part_id + part_type_id,备件库存按部件级挂载,实现"换了这个轴承,这条工单的成本记到这个部件上"。

三、保养计划:三张表拆出规则的全部维度

保养计划的建模目标是把"什么设备、做什么事、按什么周期、做到什么程度"四个问题拆干净:

sql 复制代码
-- 1. 计划头:绑定设备 + 状态
CREATE TABLE maintenance_plan (
    id           BIGINT PRIMARY KEY AUTO_INCREMENT,
    tenant_id    BIGINT NOT NULL,
    device_id    BIGINT NOT NULL,
    plan_name    VARCHAR(128) NOT NULL,
    plan_status  TINYINT NOT NULL DEFAULT 1 COMMENT '1启用2停用',
    crew_id      BIGINT COMMENT '默认责任班组',
    biz_key_rule VARCHAR(64) COMMENT '幂等键规则',
    UNIQUE KEY uk_tenant_device_name (tenant_id, device_id, plan_name)
);

-- 2. 保养项:计划做什么(可打包成组)
CREATE TABLE maintenance_item (
    id           BIGINT PRIMARY KEY AUTO_INCREMENT,
    plan_id      BIGINT NOT NULL,
    item_name    VARCHAR(128) NOT NULL COMMENT '如:更换空滤',
    std_hours    DECIMAL(5,2) COMMENT '标准工时',
    require_photo TINYINT DEFAULT 0 COMMENT '是否强制拍照',
    item_group   VARCHAR(64) COMMENT '同组保养项打包成一张工单',
    sort_no      INT
);

-- 3. 周期规则:按什么节奏(与保养项多对一或挂在计划头)
CREATE TABLE maintenance_cycle (
    id            BIGINT PRIMARY KEY AUTO_INCREMENT,
    plan_id       BIGINT NOT NULL,
    cycle_type    TINYINT NOT NULL COMMENT '1固定日历2累计量',
    interval_days INT COMMENT '类型1:间隔天数',
    day_of_month  INT COMMENT '类型1:每月几号(可空,用间隔则不填)',
    metric_code   VARCHAR(32) COMMENT '类型2:累计量测点编码',
    metric_step   DECIMAL(12,2) COMMENT '类型2:如每500小时',
    shift_days    INT DEFAULT 0 COMMENT '最多顺延天数',
    CHECK (NOT (cycle_type = 1 AND interval_days IS NULL AND day_of_month IS NULL)),
    CHECK (NOT (cycle_type = 2 AND (metric_code IS NULL OR metric_step IS NULL)))
);

两个建模决策值得展开:

  • 周期规则和保养项分开,是因为同一个计划里"点检"是每天、"换油"是每 90 天------粒度不齐是常态,分开建模才不会把计划拆得支离破碎。排程时按"周期规则 × 该规则覆盖的保养项"生成工单。
  • CHECK 约束写进库:周期类型与参数的对应关系光靠应用层校验,总有绕过 ORM 的脚本把它写脏。数据库层的 CHECK 是最后一道闸,上线以来抓过两次导入脚本的脏数据。

四、工单关联:快照思想,别只存外键

工单表关联设备和计划时,只存 device_id / plan_id 外键是不够的。设备后来改名、保养项后来调整内容,历史工单显示的信息就会"穿越"。

我们的做法是生成工单时冗余快照字段device_name_snapshotplan_name_snapshotitem_list_snapshot(JSON)。展示用快照,统计关联用外键。这与第二篇讲的"缓存一致性"呼应:设备改名时快照不更新,界面标注"下单时设备名称",反而成为追溯利器。

五、范式取舍:哪里允许冗余

最后回答一个高频问题:这套模型哪里违反了范式、为什么允许?

  1. 工单冗余设备/计划快照(上面说的):用空间换历史正确性。
  2. location_path 冗余树结构:用写时维护换查询性能。
  3. 备件出入库单冗余当时单价:成本核算不能用物料主数据的现价,必须用出入库时刻的价格。

这三处冗余的共同点是:冗余的是"事实的历史快照",而不是"当前状态"。当前状态冗余(比如工单里存设备当前状态)才是真正危险的,那会让数据自相矛盾。

六、踩坑记录

**坑一:JSON 列被当垃圾桶。**没有 Schema 约束的阶段,attrs 里混进了十几种写法(exhaust/exhaust_m3/排气量)。治理:JSON Schema 校验进代码审查清单 + 定期跑结构扫描脚本,发现未知字段告警。

**坑二:租户表漏了 tenant_id。**新加的 maintenance_item 表建表时漏了租户列,多租户查询靠 ORM 拦截器兜底才发现,差点越权。之后建表模板里 tenant_id 是默认列,Code Review 见到无租户列的业务表直接打回。

**坑三:软删字段的不一致。**有的表用 is_deleted,有的用 status=3,连表查询时漏条件就出鬼数据。统一规约:业务实体表一律 status(含"已删除"语义),日志类表物理删除。

写在最后

数据模型是设备管理系统里改造成本最高的部分------代码可以重写,数据的迁移和兼容是钝刀子割肉。值得花掉项目前期 20% 的时间把模型做对:属性分离、树结构带路径、规则拆细、快照冗余,这四个决策在我们后续所有项目里都被原样复用。

相关推荐
dixiuapp1 个月前
设备报修系统安全作业能力横评:的修、Limble与Hippo检查清单谁更严?
售后工单管理系统·设备报修系统·设备运维管理·运维报修系统·售后报修管理系统
售意达3 个月前
破解设备维保追溯难题,全生命周期管理系统赋能企业高效运维
售后服务管理系统·设备运维管理系统·售后管理系统·设备售后管理系统·设备售后工单系统
售意达3 个月前
门店设备频繁损坏,如何通过预防性维保与系统自动化巡检降低故障率?
预测性维护·设备运维管理系统·商用设备管理·设备巡检保养管理·设备售后管理系统
springfancy20136 个月前
数字化运维实践:如何构建全场景、智能化的设备管理系统?
运维·设备管理系统·设备维保管理系统·设备运维管理系统·设备保养管理系统
中设智控9 个月前
采集系统连 ERP:告别手动录入,让数据自动驱动制造效率
制造·数据采集·erp·设备管理·设备管理系统·工业软件·工业数采
中设智控9 个月前
声振温系统:提前 7 天揪故障
设备管理·设备管理系统·设备状态监测·设备监测·声振温·声振温系统
dephixf10 个月前
工业级部署指南:在西门子IOT2050(Debian 12)上搭建.NET 9.0环境与应用部署(进阶篇)
asp.net core·iot·设备管理系统·.net 9·能源管理监控系统
设备管理系统-YDYD1 年前
设备 AI 知识库,管理效率新飞跃
人工智能·设备管理·设备管理系统
PreMaint3 年前
如何改善设备综合效率(OEE)并提高工厂的生产力
科技·预测性维护·设备管理系统·premaint设备数字化平台·设备健康管理·设备综合效率·oee