3. 测试数据模型设计
在测试结果追溯系统中,数据模型决定了“能不能追溯、追溯得多快、追溯得多准”。很多项目一开始只建一张大表,把产品条码、工位、测试项、测量值、上下限、结论全部塞在一起,短期看似省事,一旦要按序列回放、按步骤统计不良、按版本对比限值,就会陷入重复数据、更新异常和查询缓慢的困境。本节围绕五个核心实体——测试项目、测试序列、测试步骤、测量结果、判定结论——讨论实体关系、主键与外键设计,以及规范化与反规范化的取舍。
一、五个核心实体的职责边界
先把每个实体“管什么”界定清楚,是建模的第一步。
- 测试项目(TestItem):描述“测什么”,是限值与判定规则的载体。典型字段包括项目编号、项目名称、单位、量程、下限、上限、判定方式(上下限、单边、枚举、文本匹配)、适用产品型号、版本号。它是相对静态的字典数据。
- 测试序列(TestSequence):描述“按什么顺序测”,是测试项目的有序集合,对应一个产品型号或工艺路线。典型字段包括序列编号、序列名称、适用型号、版本、生效日期。
- 测试步骤(TestStep):序列与项目之间的“连接实体”,描述“第几步测哪个项目、用什么条件测”。典型字段包括步骤序号、所属序列、引用项目、采集通道、激励条件、延时、重试次数。它把“顺序”和“项目”解耦。
- 测量结果(Measurement):描述“实际测到了什么”,是每次执行产生的事实数据。典型字段包括结果ID、产品条码、序列、步骤、测量值、单位、采集时间、设备编号、操作员。
- 判定结论(Verdict):描述“这一步/这一台是否合格”,以及依据。典型字段包括结论ID、关联测量结果、判定结果(Pass/Fail/Retest)、判定依据(引用的限值快照)、判定时间。
关键点在于:测量结果与判定结论应分开存储。测量值是客观事实,判定结论是依据规则产生的主观判断。若把两者混在一列,一旦限值调整或判定规则升级,历史数据的“当时判定”就无法还原,追溯会失真。
二、实体关系与主外键设计
五个实体构成一条清晰的引用链:测试序列 1—N 测试步骤,测试项目 1—N 测试步骤,测试步骤 1—N 测量结果,测量结果 1—1 判定结论。下面用一张关系图呈现主键、外键与基数。
主键选择上,建议使用无业务含义的代理键(自增整数或GUID)作为物理主键,同时为业务编号建立唯一约束。原因是项目编号、序列编号可能随版本调整,若直接用作主键,历史数据的外键会随之漂移。外键方面,测量结果必须携带步骤ID,而步骤ID又指向序列与项目,因此“条码→序列→步骤→项目→限值”的完整追溯路径可以通过三次连接完成。
三、规范化:先做对,再谈快
按第三范式设计,上述五张表基本消除了传递依赖:项目限值只存一份,序列顺序只存一份,测量事实只存一份。这样带来的直接好处是:修改某项目上限,只需改一行;新增一个步骤,不影响历史测量;统计某型号某项目的不良率,只需按外键聚合。
但纯规范化在测试场景会遇到两个现实问题。第一,测量结果表数据量极大,一次产线测试可能每秒写入数十条,若每次判定都要回连项目表取限值,高频写入下连接开销明显。第二,历史追溯要求“还原当时判定”,而项目表的限值会随版本更新,若判定结论只存外键,回看旧数据时取到的是新限值,结论就错了。
四、反规范化:把“当时快照”固化下来
针对上述问题,常用的反规范化手段是在测量结果或判定结论中冗余关键字段。典型做法是在判定结论中冗余 LSL、USL、判定方式、规则版本号,形成“限值快照”。这样即使项目表后续修改,历史判定仍可原样复现。另一个做法是在测量结果中冗余项目编号与序列编号,减少追溯查询的连接次数。
反规范化的代价是写入时需保证冗余字段与主表一致。工程上通常用两种方式控制:一是由写入程序在插入时统一填充快照字段,二是对字典表采用“只增不改”的版本化策略——修改限值不覆盖旧行,而是新增一条带新版本号的项目记录,旧测量仍指向旧版本。后者更彻底,但要求所有查询都带版本条件。
五、一个可落地的建表示例
下面给出核心表的简化DDL,体现主键、外键与快照字段的设计意图(以通用SQL语法示意,具体类型可按数据库调整)。
CREATE TABLE TestItem (
ItemID INTEGER PRIMARY KEY,
ItemCode VARCHAR(32) UNIQUE NOT NULL,
ItemName VARCHAR(64) NOT NULL,
Unit VARCHAR(16),
LSL DECIMAL(12,4),
USL DECIMAL(12,4),
JudgeMode VARCHAR(16), -- Limit/OneSide/Enum/Text
Version INTEGER NOT NULL
);
CREATE TABLE TestSequence (
SeqID INTEGER PRIMARY KEY,
SeqCode VARCHAR(32) UNIQUE NOT NULL,
SeqName VARCHAR(64),
ModelCode VARCHAR(32),
Version INTEGER NOT NULL,
ActiveFlag SMALLINT DEFAULT 1
);
CREATE TABLE TestStep (
StepID INTEGER PRIMARY KEY,
SeqID INTEGER NOT NULL REFERENCES TestSequence(SeqID),
ItemID INTEGER NOT NULL REFERENCES TestItem(ItemID),
StepNo INTEGER NOT NULL,
Channel VARCHAR(16),
DelayMs INTEGER,
RetryTimes INTEGER DEFAULT 0
);
CREATE TABLE Measurement (
MeasID BIGINT PRIMARY KEY,
StepID INTEGER NOT NULL REFERENCES TestStep(StepID),
Barcode VARCHAR(64) NOT NULL,
MeasValue DECIMAL(14,5),
Unit VARCHAR(16),
MeasTime TIMESTAMP NOT NULL,
DeviceID VARCHAR(32),
Operator VARCHAR(32)
);
CREATE TABLE Verdict (
VerdictID BIGINT PRIMARY KEY,
MeasID BIGINT NOT NULL REFERENCES Measurement(MeasID),
Result VARCHAR(8) NOT NULL, -- Pass/Fail/Retest
LSL_Snap DECIMAL(12,4), -- 限值快照
USL_Snap DECIMAL(12,4),
RuleVersion INTEGER,
JudgeTime TIMESTAMP NOT NULL
);
建表后应重点验证三件事:一是插入一条测量后,能否仅凭条码查出其序列、步骤、项目与判定依据;二是修改某项目限值后,旧判定结论是否保持不变;三是按“型号+项目+时间段”统计不良率时,查询计划是否走外键索引。若第二点不成立,说明快照字段缺失或版本策略未落实,需要回到判定结论表补冗余。
六、索引与查询路径
追溯查询最常见的入口是产品条码,因此 Measurement 表应在 Barcode 上建索引,并考虑 (Barcode, MeasTime) 复合索引以支持按时间排序回放。按步骤统计时,StepID 外键索引必不可少。Verdict 表通过 MeasID 与测量结果一对一关联,MeasID 上建唯一索引可同时保证一对一约束与查询效率。
需要提醒的是,反规范化字段不要参与高频过滤条件,否则一旦快照与主表不一致,过滤结果会自相矛盾。快照字段的定位是“展示与复现”,不是“检索主依据”。检索仍应走规范化外键,展示时再取快照,这样既保证一致性,又保留追溯能力。
综上,测试数据模型的设计顺序应是:先按实体职责划清边界,用代理主键与业务唯一键分离,用外键串起序列—步骤—测量—判定链路;再在事实表上做有限反规范化,固化限值快照与规则版本;最后用索引支撑条码追溯与统计聚合。这样得到的模型既能正确回答“这台产品当时按什么规则判的”,也能高效回答“这个项目最近的不良趋势如何”。