一、为什么硅片 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 追溯路径
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 追溯路径
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 打通上下游。正向追溯从物料或设备出发向下游扩散,逆向追溯从电池片或组件出发向上游回溯,两者共用同一套表结构,只是查询方向和索引选择不同。
落地时优先保证三件事:事件表只追加不修改、拆合批血缘关系完整、关键查询字段索引到位。做到这三点,即使面对千万级电池片和亿级过站记录,也能在秒级完成一次完整追溯。