太阳能硅片 MES 系统中的正向追溯与逆向追溯:基于电池片 ID 与批次号的 MySQL 实现

一、为什么硅片 MES 必须做好追溯

太阳能电池片生产是一条典型的连续流加离散混合的制造过程:从硅片投料、清洗制绒、扩散、刻蚀、镀膜、丝网印刷到测试分选,动辄上百道工序,中间还伴随批次拆分、合批、返工、补片等操作。一旦客户端出现功率衰减异常、EL 隐裂、PID 失效等问题,如果无法在几小时内定位到具体的硅片供应商、扩散炉管、PECVD 腔体、丝网印刷机台和当班班组,就只能整批召回,损失巨大。

因此,硅片 MES 的追溯能力通常被拆成两个方向:

  • 正向追溯(Forward Trace):已知某个原材料批次、某台设备、某个工艺参数或某个时间窗口,向下游查找它影响了哪些电池片、哪些组件批次、发往了哪些客户。
  • 逆向追溯(Backward Trace):已知某个电池片 ID 或客户投诉的组件批次,向上游回溯它经过了哪些工序、用了哪批硅片、哪批浆料、哪台设备、哪个工艺配方。

两者本质上是同一张追溯关系图的两个遍历方向,工程实现上共用一套数据模型,只是查询入口和遍历方向不同。

二、追溯的两个核心标识:电池片 ID 与批次号

2.1 电池片 ID(Cell ID)

电池片 ID 是单片的唯一身份,通常在丝网印刷或测试分选环节通过激光打码、喷码或 OCR 读码产生,并伴随电池片走完剩余生命周期。它的特点是:

  • 唯一性:一片一码,全局唯一,建议使用定长字符串(如 20 位)并带校验位。
  • 可读性:编码中可嵌入产线、班次、日期、流水号,便于人工识别。
  • 不可变性:一旦生成不再修改,返工也只追加记录,不覆盖原 ID。

典型编码规则示例:L1-20261029-A-000123,分别表示产线、日期、班次、流水号。

2.2 批次号(Lot ID)

批次号是工艺流转的最小管理单元,一个批次通常包含 400~1200 片电池片。批次号在投料时生成,随工艺路线流转,遇到拆分、合批、返工时会产生新的批次号,并通过父子关系表记录血缘。

批次号的关键设计点:

  • 批次与片的关系是一对多,但会随拆批、并批动态变化,因此不能只在批次表里存一个片数,必须有明细关系表。
  • 批次号需要记录来源批次,用于逆向追溯时还原拆合历史。
  • 批次号与工单、产品型号、硅片供应商批次绑定,这是正向追溯的关键入口。

三、追溯数据模型设计

追溯系统的核心是「事件流 + 关系表」。所有工序过站都写入一条不可变的事件记录,再通过关系表把片、批次、设备、物料、工单串起来。下面给出 MySQL 的核心表设计。

3.1 电池片主表 cell_info

sql 复制代码
CREATE TABLE cell_info (
  cell_id        VARCHAR(32)  NOT NULL COMMENT '电池片唯一ID',
  lot_id         VARCHAR(32)  NOT NULL COMMENT '当前所属批次号',
  work_order_no  VARCHAR(32)  NOT NULL COMMENT '工单号',
  product_code   VARCHAR(32)  NOT NULL COMMENT '产品型号',
  wafer_lot_no   VARCHAR(32)  DEFAULT NULL COMMENT '硅片来料批次',
  current_step   VARCHAR(32)  DEFAULT NULL COMMENT '当前工序',
  cell_status    TINYINT      NOT NULL DEFAULT 0 COMMENT '0在制 1完工 2报废 3返工',
  create_time    DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP,
  update_time    DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (cell_id),
  KEY idx_lot (lot_id),
  KEY idx_wafer_lot (wafer_lot_no),
  KEY idx_work_order (work_order_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='电池片主表';

这张表是逆向追溯的起点:拿到 cell_id 就能立刻知道它属于哪个批次、哪个工单、用的哪批硅片。

3.2 批次主表 lot_info

sql 复制代码
CREATE TABLE lot_info (
  lot_id         VARCHAR(32) NOT NULL COMMENT '批次号',
  parent_lot_id  VARCHAR(32) DEFAULT NULL COMMENT '父批次号(拆批/合批来源)',
  lot_type       TINYINT     NOT NULL DEFAULT 0 COMMENT '0正常 1拆批 2合批 3返工',
  work_order_no  VARCHAR(32) NOT NULL,
  product_code   VARCHAR(32) NOT NULL,
  wafer_lot_no   VARCHAR(32) DEFAULT NULL,
  qty            INT         NOT NULL DEFAULT 0 COMMENT '批次片数',
  current_step   VARCHAR(32) DEFAULT NULL,
  lot_status     TINYINT     NOT NULL DEFAULT 0,
  create_time    DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (lot_id),
  KEY idx_parent (parent_lot_id),
  KEY idx_wafer_lot (wafer_lot_no),
  KEY idx_work_order (work_order_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='批次主表';

3.3 批次-电池片关系表 lot_cell_rel

由于拆批、并批的存在,片与批次是多对多关系,必须单独建关系表,并记录生效时间段。

sql 复制代码
CREATE TABLE lot_cell_rel (
  id          BIGINT      NOT NULL AUTO_INCREMENT,
  lot_id      VARCHAR(32) NOT NULL,
  cell_id     VARCHAR(32) NOT NULL,
  bind_time   DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '绑定时间',
  unbind_time DATETIME    DEFAULT NULL COMMENT '解绑时间,拆批时写入',
  is_active   TINYINT     NOT NULL DEFAULT 1 COMMENT '1当前有效 0历史',
  PRIMARY KEY (id),
  KEY idx_lot_cell (lot_id, cell_id),
  KEY idx_cell (cell_id, is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='批次与电池片关系表';

3.4 工序过站事件表 process_event

这是追溯系统数据量最大、也最关键的一张表。每一次过站、每一次参数采集都写一条记录,只追加不修改。

sql 复制代码
CREATE TABLE process_event (
  event_id      BIGINT       NOT NULL AUTO_INCREMENT,
  cell_id       VARCHAR(32)  NOT NULL,
  lot_id        VARCHAR(32)  NOT NULL,
  step_code     VARCHAR(32)  NOT NULL COMMENT '工序编码,如 DIFFUSION',
  step_name     VARCHAR(64)  NOT NULL,
  equipment_id  VARCHAR(32)  DEFAULT NULL COMMENT '设备编号',
  chamber_id    VARCHAR(32)  DEFAULT NULL COMMENT '腔体/炉管编号',
  recipe_id     VARCHAR(32)  DEFAULT NULL COMMENT '工艺配方',
  operator_id   VARCHAR(32)  DEFAULT NULL,
  shift_code    VARCHAR(16)  DEFAULT NULL,
  in_time       DATETIME     NOT NULL COMMENT '进站时间',
  out_time      DATETIME     DEFAULT NULL COMMENT '出站时间',
  result        TINYINT      NOT NULL DEFAULT 1 COMMENT '1合格 2不合格 3返工',
  param_json    JSON         DEFAULT NULL COMMENT '工艺参数快照',
  PRIMARY KEY (event_id),
  KEY idx_cell_time (cell_id, in_time),
  KEY idx_lot_step (lot_id, step_code),
  KEY idx_equip_time (equipment_id, in_time),
  KEY idx_step_time (step_code, in_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工序过站事件表';

注意 param_json 字段:不同工序参数差异极大(扩散要记温度、时间、方阻;PECVD 要记功率、气压、气体流量),用 JSON 存快照比给每道工序建一张参数表更灵活,MySQL 5.7 以上支持 JSON 类型和虚拟列索引。

3.5 物料投料关系表 material_consume

正向追溯要回答「这批硅片/浆料用到了哪些电池片」,就必须记录物料消耗关系。

sql 复制代码
CREATE TABLE material_consume (
  id            BIGINT      NOT NULL AUTO_INCREMENT,
  material_type VARCHAR(16) NOT NULL COMMENT 'WAFER/PASTE/GAS/TARGET',
  material_lot  VARCHAR(32) NOT NULL COMMENT '物料批次号',
  lot_id        VARCHAR(32) NOT NULL COMMENT '消耗该物料的电池片批次',
  step_code     VARCHAR(32) NOT NULL,
  equipment_id  VARCHAR(32) DEFAULT NULL,
  consume_time  DATETIME    NOT NULL,
  qty           DECIMAL(12,3) DEFAULT NULL,
  PRIMARY KEY (id),
  KEY idx_material (material_type, material_lot),
  KEY idx_lot (lot_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物料消耗关系表';

3.6 组件绑定表 module_cell_rel

电池片最终要装成组件,追溯链路必须延伸到组件和客户。

sql 复制代码
CREATE TABLE module_cell_rel (
  id          BIGINT      NOT NULL AUTO_INCREMENT,
  module_sn   VARCHAR(32) NOT NULL COMMENT '组件序列号',
  cell_id     VARCHAR(32) NOT NULL,
  position_no VARCHAR(16) DEFAULT NULL COMMENT '组件内位置号',
  bind_time   DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id),
  KEY idx_module (module_sn),
  KEY idx_cell (cell_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='组件与电池片绑定表';

四、正向追溯的实现

正向追溯的典型场景:硅片供应商反馈某批来料存在氧含量偏高问题,需要找出用了这批硅片的所有电池片和组件。

4.1 追溯路径

flowchart LR A[硅片来料批次 wafer_lot_no] --> B[lot_info 批次] B --> C[lot_cell_rel 电池片] C --> D[process_event 工序记录] C --> E[module_cell_rel 组件] E --> F[客户/发货单]

4.2 核心 SQL

第一步,从硅片批次找到受影响的电池片批次:

sql 复制代码
SELECT lot_id, work_order_no, qty, create_time
FROM lot_info
WHERE wafer_lot_no = 'WF20261015001';

第二步,展开到具体电池片:

sql 复制代码
SELECT r.cell_id, r.lot_id, c.current_step, c.cell_status
FROM lot_cell_rel r
JOIN cell_info c ON c.cell_id = r.cell_id
WHERE r.lot_id IN (
  SELECT lot_id FROM lot_info WHERE wafer_lot_no = 'WF20261015001'
)
AND r.is_active = 1;

第三步,继续向下游找到组件和客户:

sql 复制代码
SELECT m.module_sn, m.cell_id, m.position_no
FROM module_cell_rel m
WHERE m.cell_id IN (
  SELECT r.cell_id
  FROM lot_cell_rel r
  JOIN lot_info l ON l.lot_id = r.lot_id
  WHERE l.wafer_lot_no = 'WF20261015001'
);

如果数据量大,建议把这三步做成异步任务,结果落到一张 trace_result 临时表,前端分页展示,避免一次性 JOIN 打爆数据库。

4.3 按设备或时间窗口正向追溯

更常见的场景是设备异常:某台扩散炉在 10 月 20 日 14:00~16:00 炉温异常,需要找出这段时间过站的所有电池片。

sql 复制代码
SELECT DISTINCT cell_id, lot_id
FROM process_event
WHERE equipment_id = 'DIFF-03'
  AND step_code = 'DIFFUSION'
  AND in_time BETWEEN '2026-10-20 14:00:00' AND '2026-10-20 16:00:00';

这里 idx_equip_time 索引非常关键,否则全表扫描在千万级事件表上会直接超时。

五、逆向追溯的实现

逆向追溯的典型场景:客户投诉某块组件功率异常,需要回溯到具体电池片、工序、设备和原材料。

5.1 追溯路径

flowchart RL A[组件序列号 module_sn] --> B[module_cell_rel 电池片] B --> C[process_event 工序事件] C --> D[设备/腔体/配方] B --> E[lot_info 批次] E --> F[硅片来料批次/浆料批次]

5.2 核心 SQL

第一步,从组件找到电池片:

sql 复制代码
SELECT cell_id, position_no
FROM module_cell_rel
WHERE module_sn = 'MOD2026102800123';

第二步,查该电池片的完整工序履历:

sql 复制代码
SELECT step_code, step_name, equipment_id, chamber_id,
       recipe_id, operator_id, in_time, out_time, result, param_json
FROM process_event
WHERE cell_id = 'L1-20261029-A-000123'
ORDER BY in_time;

第三步,回溯批次和原材料:

sql 复制代码
SELECT l.lot_id, l.wafer_lot_no, l.work_order_no, l.parent_lot_id,
       m.material_type, m.material_lot, m.consume_time
FROM lot_info l
LEFT JOIN material_consume m ON m.lot_id = l.lot_id
WHERE l.lot_id = (
  SELECT lot_id FROM cell_info WHERE cell_id = 'L1-20261029-A-000123'
);

5.3 处理拆批与合批的血缘回溯

如果批次经过拆批,parent_lot_id 会形成一条链。MySQL 8.0 可以用递归 CTE 一次性回溯到根批次:

sql 复制代码
WITH RECURSIVE lot_chain AS (
  SELECT lot_id, parent_lot_id, lot_type, wafer_lot_no, 1 AS lvl
  FROM lot_info
  WHERE lot_id = 'LOT20261029A003'
  UNION ALL
  SELECT p.lot_id, p.parent_lot_id, p.lot_type, p.wafer_lot_no, c.lvl + 1
  FROM lot_info p
  JOIN lot_chain c ON p.lot_id = c.parent_lot_id
  WHERE c.lvl < 10
)
SELECT * FROM lot_chain ORDER BY lvl;

MySQL 5.7 不支持递归 CTE,需要在应用层循环查询,或者预先在 lot_info 中冗余一个 root_lot_id 字段,用空间换时间。

六、性能与工程实践要点

6.1 分表与分区

process_event 是增长最快的表,一条产线一天可能产生数百万条记录。建议:

  • 按 in_time 做 RANGE 分区,按月或按周分区,历史分区可归档到冷存储。
  • 按产线或工厂做水平分库,避免单表过大。
  • 追溯查询只查最近 3 个月热数据,更早的数据走归档库。

6.2 索引设计原则

  • 逆向追溯入口是 cell_id,必须有 (cell_id, in_time) 联合索引。
  • 正向追溯入口是 lot_id、equipment_id、wafer_lot_no,分别建索引。
  • 避免在 param_json 上做模糊查询,如需按参数筛选,用虚拟列 + 索引。

6.3 数据一致性

过站事件写入必须与批次状态更新在同一事务内,避免出现「事件写了但批次没更新」的脏数据。对于高并发过站,建议用消息队列削峰,由消费者批量落库,同时保证幂等(以 cell_id + step_code + in_time 做唯一约束)。

6.4 追溯结果可视化

前端通常用树形图或桑基图展示追溯链路:正向追溯展示「物料 → 批次 → 电池片 → 组件 → 客户」,逆向追溯展示「组件 → 电池片 → 工序 → 设备 → 物料」。数据量大时只展示聚合节点,点击下钻再查明细。

七、总结

太阳能硅片 MES 的追溯能力,本质上是把「片」和「批」两条主线用事件流串起来:cell_info 和 lot_info 定义身份,lot_cell_rel 维护动态归属,process_event 记录全过程,material_consume 和 module_cell_rel 打通上下游。正向追溯从物料或设备出发向下游扩散,逆向追溯从电池片或组件出发向上游回溯,两者共用同一套表结构,只是查询方向和索引选择不同。

落地时优先保证三件事:事件表只追加不修改、拆合批血缘关系完整、关键查询字段索引到位。做到这三点,即使面对千万级电池片和亿级过站记录,也能在秒级完成一次完整追溯。

相关推荐
IT古董10 小时前
SIP 与 SOP 详解:制造业标准化作业与生产流程管理
mes
IT古董3 天前
GMP(Good Manufacturing Practice,良好生产规范)
mes
慧都小妮子6 天前
DXPServer OPC UA安全连接怎么配?
数据采集·opc ua·工业通信·mes·dxpserver
晶捷软件6 天前
离散制造系统集成实战:PLM/ERP/MES/WMS 数据流设计与五个踩坑复盘
制造·智能制造·erp·mes·制造业信息化
龙鼎源数智9 天前
家居行业 ERP 与 MES 的区别:系统边界、数据流与集成落点
智能制造·erp·系统集成·mes
AX-MES11 天前
AX-MES生产制造管理系统-常用电子报表
mes·生产管理·品质管理·车间管理·异常管理
CORNERSTONE36512 天前
准备上MES,企业要先整理哪些基础数据?
低代码·erp·mes·企业数字化
️公子15 天前
胶带缠完还不算:扎带绑扎的张力间距、锁向防松与 MES 闸门
mes·线束·扎带·绑扎·束扎·防错·张力
️公子1 个月前
外观也过了?包装贴标、条码绑定与出货 MES 闸门
智能制造·mes·线束·条码·工艺软件