05 - MES 数据库设计
目标读者:数据库管理员、后端开发工程师
阅读时间:约 25 分钟
前置知识:关系数据库基础、MySQL
一、数据模型设计
1.1 E-R 关系总览
1.2 关键实体关系
| 实体 A |
关系 |
实体 B |
说明 |
| Product |
1 : N |
WorkOrder |
一个产品对应多张工单 |
| WorkOrder |
1 : N |
WorkOrderRouting |
一张工单对应多条工序记录 |
| WorkOrderRouting |
1 : N |
QualityInspection |
每道工序可产生多条检验记录 |
| Product |
1 : N |
BOM |
一个产品对应多行 BOM |
| BOM |
N : 1 |
Material |
BOM 行关联物料 |
| MaterialLot |
N : 1 |
Material |
物料批次关联物料主数据 |
| WorkOrderRouting |
N : 1 |
Equipment |
工序关联加工设备 |
| MaintenanceRecord |
N : 1 |
Equipment |
维护记录关联设备 |
二、核心表结构设计
2.1 工单表 (work_order)
CREATE TABLE work_order (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
order_no VARCHAR(50) NOT NULL UNIQUE COMMENT '工单号,如 WO-20260729-001',
product_id BIGINT NOT NULL COMMENT '产品ID',
product_code VARCHAR(50) NOT NULL COMMENT '产品编码(冗余字段)',
product_name VARCHAR(200) NOT NULL COMMENT '产品名称(冗余字段)',
order_qty INT NOT NULL COMMENT '计划生产数量',
completed_qty INT DEFAULT 0 COMMENT '已完成数量',
qualified_qty INT DEFAULT 0 COMMENT '合格数量',
defective_qty INT DEFAULT 0 COMMENT '不良品数量',
plan_start_time DATETIME COMMENT '计划开始时间',
plan_end_time DATETIME COMMENT '计划结束时间',
actual_start_time DATETIME COMMENT '实际开始时间',
actual_end_time DATETIME COMMENT '实际结束时间',
status VARCHAR(20) NOT NULL DEFAULT 'CREATED' COMMENT '状态:CREATED|SCHEDULED|DISPATCHED|IN_PRODUCTION|COMPLETED|CLOSED',
priority TINYINT DEFAULT 5 COMMENT '优先级 1-10,1最高',
line_id BIGINT COMMENT '产线ID',
erp_order_no VARCHAR(50) COMMENT 'ERP计划单号',
remark VARCHAR(500) COMMENT '备注',
created_by VARCHAR(50) COMMENT '创建人',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_status (status),
INDEX idx_product_id (product_id),
INDEX idx_plan_start (plan_start_time),
INDEX idx_erp_order (erp_order_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生产工单表';
2.2 工序明细表 (work_order_routing)
CREATE TABLE work_order_routing (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
work_order_id BIGINT NOT NULL COMMENT '工单ID',
order_no VARCHAR(50) NOT NULL COMMENT '工单号(冗余)',
operation_seq INT NOT NULL COMMENT '工序序号(1, 2, 3...)',
operation_code VARCHAR(50) NOT NULL COMMENT '工序代码',
operation_name VARCHAR(100) NOT NULL COMMENT '工序名称',
equipment_id BIGINT COMMENT '加工设备ID',
standard_time INT COMMENT '标准工时(秒)',
actual_time INT COMMENT '实际工时(秒)',
planned_qty INT COMMENT '计划数量',
completed_qty INT DEFAULT 0 COMMENT '完成数量',
qualified_qty INT DEFAULT 0 COMMENT '合格数量',
defective_qty INT DEFAULT 0 COMMENT '不良品数量',
status VARCHAR(20) DEFAULT 'PENDING' COMMENT 'PENDING|IN_PROCESS|COMPLETED|SKIPPED',
actual_start_time DATETIME COMMENT '实际开始时间',
actual_end_time DATETIME COMMENT '实际结束时间',
operator_id BIGINT COMMENT '操作员ID',
remark VARCHAR(500),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_work_order (work_order_id),
INDEX idx_status (status),
UNIQUE KEY uk_wo_op (work_order_id, operation_seq)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工单工序明细表';
2.3 产品表 (product)
CREATE TABLE product (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
product_code VARCHAR(50) NOT NULL UNIQUE COMMENT '产品编码',
product_name VARCHAR(200) NOT NULL COMMENT '产品名称',
product_type VARCHAR(50) COMMENT '产品类型(成品/半成品/原材料)',
specification VARCHAR(500) COMMENT '规格描述',
unit VARCHAR(20) DEFAULT 'PCS' COMMENT '计量单位',
version VARCHAR(20) DEFAULT 'A' COMMENT '版本号',
drawing_no VARCHAR(50) COMMENT '图号',
status VARCHAR(20) DEFAULT 'ACTIVE' COMMENT 'ACTIVE|OBSOLETED',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产品主数据表';
2.4 BOM 表 (bom)
CREATE TABLE bom (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
product_id BIGINT NOT NULL COMMENT '成品/半成品ID',
material_id BIGINT NOT NULL COMMENT '物料ID',
material_code VARCHAR(50) NOT NULL COMMENT '物料编码(冗余)',
material_name VARCHAR(200) NOT NULL COMMENT '物料名称(冗余)',
qty_per_unit DECIMAL(10,3) NOT NULL COMMENT '单件用量',
unit VARCHAR(20) DEFAULT 'PCS',
position VARCHAR(50) COMMENT '位号(电子行业)',
version VARCHAR(20) DEFAULT 'A' COMMENT 'BOM版本',
status VARCHAR(20) DEFAULT 'ACTIVE',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_product (product_id),
INDEX idx_material (material_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物料清单表';
2.5 物料主数据表 (material)
CREATE TABLE material (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
material_code VARCHAR(50) NOT NULL UNIQUE COMMENT '物料编码',
material_name VARCHAR(200) NOT NULL COMMENT '物料名称',
material_type VARCHAR(50) COMMENT '物料类型(原材料/辅料/包材)',
specification VARCHAR(500) COMMENT '规格',
unit VARCHAR(20) DEFAULT 'PCS',
supplier_id BIGINT COMMENT '主要供应商',
safety_stock INT DEFAULT 0 COMMENT '安全库存',
status VARCHAR(20) DEFAULT 'ACTIVE',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物料主数据表';
2.6 物料批次表 (material_lot)
CREATE TABLE material_lot (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
lot_no VARCHAR(50) NOT NULL COMMENT '批次号',
material_id BIGINT NOT NULL COMMENT '物料ID',
material_code VARCHAR(50) NOT NULL COMMENT '物料编码(冗余)',
supplier VARCHAR(100) COMMENT '供应商',
qty INT NOT NULL COMMENT '数量',
received_date DATE COMMENT '收货日期',
expire_date DATE COMMENT '有效期',
status VARCHAR(20) DEFAULT 'NORMAL' COMMENT 'NORMAL|LOCKED|EXHAUSTED',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_lot (lot_no, material_id),
INDEX idx_material (material_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物料批次表';
2.7 物料绑定表 (material_usage)
CREATE TABLE material_usage (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
work_order_id BIGINT NOT NULL COMMENT '工单ID',
routing_id BIGINT NOT NULL COMMENT '工序明细ID',
material_lot_id BIGINT NOT NULL COMMENT '物料批次ID',
material_code VARCHAR(50) NOT NULL,
lot_no VARCHAR(50) NOT NULL COMMENT '批次号(冗余)',
used_qty DECIMAL(10,3) NOT NULL COMMENT '实际用量',
operator_id BIGINT COMMENT '操作员ID',
scan_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '扫码时间',
INDEX idx_work_order (work_order_id),
INDEX idx_routing (routing_id),
INDEX idx_lot (material_lot_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物料使用绑定表(追溯核心表)';
2.8 质量检验表 (quality_inspection)
CREATE TABLE quality_inspection (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
inspection_no VARCHAR(50) NOT NULL UNIQUE COMMENT '检验单号',
work_order_id BIGINT NOT NULL COMMENT '工单ID',
routing_id BIGINT COMMENT '工序明细ID(为空表示终检)',
inspection_type VARCHAR(20) NOT NULL COMMENT 'IQC|FAI|IPQC|FQC|OQC',
sample_qty INT COMMENT '抽样数量',
defect_qty INT DEFAULT 0 COMMENT '不合格数',
result VARCHAR(20) NOT NULL COMMENT 'PASS|FAIL|CONCESSION(特采)',
inspector_id BIGINT COMMENT '检验员ID',
inspection_time DATETIME DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
INDEX idx_work_order (work_order_id),
INDEX idx_routing (routing_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='质量检验记录表';
2.9 质量检验明细表 (quality_inspection_detail)
CREATE TABLE quality_inspection_detail (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
inspection_id BIGINT NOT NULL COMMENT '检验记录ID',
inspection_item VARCHAR(100) NOT NULL COMMENT '检验项目',
spec_value VARCHAR(100) COMMENT '规格值/公差范围',
actual_value VARCHAR(100) COMMENT '实际检测值',
is_pass TINYINT(1) NOT NULL COMMENT '是否合格 1=合格 0=不合格',
defect_code VARCHAR(20) COMMENT '缺陷代码',
INDEX idx_inspection (inspection_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='质量检验明细表';
2.10 设备表 (equipment)
CREATE TABLE equipment (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
equipment_code VARCHAR(50) NOT NULL UNIQUE COMMENT '设备编码',
equipment_name VARCHAR(200) NOT NULL COMMENT '设备名称',
equipment_type VARCHAR(50) COMMENT '设备类型(CNC/注塑机/冲压机等)',
line_id BIGINT COMMENT '所属产线',
status VARCHAR(20) DEFAULT 'IDLE' COMMENT 'RUNNING|IDLE|ALARM|MAINTENANCE|OFFLINE',
ip_address VARCHAR(50) COMMENT 'IP地址',
opcua_endpoint VARCHAR(200) COMMENT 'OPC UA 端点URL',
protocol VARCHAR(20) COMMENT '通信协议 (OPCUA|Modbus|MQTT)',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备主数据表';
2.11 设备维护记录表 (maintenance_record)
CREATE TABLE maintenance_record (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
equipment_id BIGINT NOT NULL COMMENT '设备ID',
maintenance_type VARCHAR(20) NOT NULL COMMENT 'DAILY_CHECK|PERIODIC|BREAKDOWN|PREDICTIVE',
plan_time DATETIME COMMENT '计划维护时间',
actual_time DATETIME COMMENT '实际维护时间',
duration INT COMMENT '维护时长(分钟)',
downtime_reason VARCHAR(200) COMMENT '停机原因',
maintenance_content TEXT COMMENT '维护内容',
technician_id BIGINT COMMENT '维修人员ID',
status VARCHAR(20) DEFAULT 'PLANNED' COMMENT 'PLANNED|IN_PROGRESS|COMPLETED',
INDEX idx_equipment (equipment_id),
INDEX idx_type (maintenance_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备维护记录表';
2.12 设备数据采集表 (device_data_point)
CREATE TABLE device_data_point (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
equipment_id BIGINT NOT NULL COMMENT '设备ID',
parameter_name VARCHAR(50) NOT NULL COMMENT '参数名(如 temperature, speed)',
parameter_value VARCHAR(50) NOT NULL COMMENT '参数值',
unit VARCHAR(20) COMMENT '单位',
collect_time DATETIME(3) NOT NULL COMMENT '采集时间戳(毫秒级)',
INDEX idx_equip_time (equipment_id, collect_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备数据采集表(高频写入)';
-- 注:生产环境建议使用 InfluxDB 或 TimescaleDB 存储设备时序数据
三、索引策略
3.1 核心索引原则
| 原则 |
说明 |
| WHERE 条件列加索引 |
status, product_id, equipment_id 等高频筛选字段 |
| 联合索引遵循最左前缀 |
INDEX idx_equip_time (equipment_id, collect_time) |
| 避免过多索引 |
每表索引数控制在 5-8 个以内,避免写性能下降 |
| 覆盖索引 |
高频查询的列尽量包含在索引中,减少回表 |
3.2 关键联合索引
-- 工单查询:按状态 + 计划时间
INDEX idx_status_plan (status, plan_start_time)
-- 工序明细:按工单 + 工序序号(唯一约束)
UNIQUE KEY uk_wo_op (work_order_id, operation_seq)
-- 设备数据:按设备 + 时间范围(时序查询)
INDEX idx_equip_time (equipment_id, collect_time)
-- 质量检验:按工单
INDEX idx_work_order (work_order_id)
四、分库分表方案
4.1 分库分表判断条件
| 条件 |
阈值 |
措施 |
| 单表数据量 |
> 500 万行 |
考虑水平分表 |
| 单库数据量 |
> 100 GB |
考虑分库 |
| QPS |
> 5000 |
读写分离 |
| 写 QPS |
> 2000 |
分库分表 |
4.2 分片策略
| 表 |
分片键 |
策略 |
说明 |
| work_order |
order_no 取模 |
按年分库 + 按 order_no 哈希 16 表 |
历史数据按年归档 |
| device_data_point |
equipment_id |
按设备哈希 32 表 |
高频写入,分散压力 |
| quality_inspection |
work_order_id |
跟随工单分片(genes) |
与工单同库,保证事务 |
| material_usage |
work_order_id |
跟随工单分片 |
与工单同库 |
4.3 归档策略
当前数据 (近 3 个月) → 热库 (SSD, 高性能)
历史数据 (3-12 个月) → 温库 (HDD,压缩)
冷数据 (> 12 个月) → 归档库/对象存储
五、数据安全与备份
5.1 备份策略
| 备份类型 |
频率 |
保留周期 |
介质 |
| 全量备份 |
每日 |
30 天 |
异地存储 |
| 增量备份 |
每小时 |
7 天 |
本地存储 |
| Binlog 备份 |
实时 |
30 天 |
本地存储 |
| 归档文件 |
每季度 |
永久 |
对象存储 |
5.2 敏感数据保护
| 字段 |
保护方式 |
说明 |
| 用户密码 |
BCrypt 加密 |
单向不可逆 |
| 身份证号 |
AES-256 加密 + 脱敏显示 |
前 3 后 4 |
| 操作日志 |
只追加写入,不修改不删除 |
审计合规 |
六、数据库选型总结
| 场景 |
推荐 |
理由 |
| 业务主数据 |
MySQL 8.0 |
稳定、生态好、运维成熟 |
| 时序数据(设备采集) |
InfluxDB / TimescaleDB |
高吞吐写入、时序压缩 |
| 高速缓存 |
Redis 7.x |
低延迟、丰富数据结构 |
| 全文搜索 |
Elasticsearch |
日志分析、模糊搜索 |
| 文件存储 |
MinIO |
|