Skip to content

数据存储、语义与追溯设计(V10)

内容类型:任务分流 + 数据设计难度:进阶适合:采样数据、测试结果、配置、日志、CSV/数据库、历史兼容和现场追溯阅读时间:约 12 分钟

数据设计不是“最后选个 CSV 还是数据库”。更重要的是:这个值是什么、来自哪里、用什么单位、什么时候写、写失败后系统做什么、以后还能不能证明当时发生了什么。

V10 同样不要求每次改一个导出列都重新设计整个存储体系。

1. 先分任务

当前任务推荐路径
“这个字段现在保存到哪里?”Read-Only Trace
增加/修改一个明确导出列Execution / MicroPatch
修改一个正式阈值/单位并影响存储DomainConstraint / Measurement Semantics
“旧版本记录正常,新版单位错了”RegressionFix
修改 Schema、历史兼容、迁移规则Execution + V2/V4 compatibility
新系统的数据/追溯方案Discovery / Data Design

小改只沿当前字段的数据链追踪,不全库扫描所有数据库和文件。

2. 先分清 6 类数据,不要全部叫“测试数据”

类型示例重点
RawData原始报文、ADC、示波器原始峰值是否能复盘底层事实
EngineeringDataA、V、℃、mm 等工程量Conversion、单位、精度
DerivedResult平均、峰值、判定、统计结果算法版本、阈值来源
Configuration参数、通道、范围、阈值owner、版本、兼容、回退
OperationalLog用户操作、状态变化谁、何时、做了什么
DiagnosticEvidence错误码、SCPI、协议原文、堆栈现场定位与证据等级

同一个项目可以只保存其中一部分,但要明确这是设计选择,不要无意间混在一起。

3. RawValue 和 EngineeringValue 不能互相冒充

典型链:

text
RawValue
→ Decode
→ Conversion
→ EngineeringValue
→ Aggregation / Threshold
→ Result
→ Display / Save / MES

例如:

text
Scope RawPeak = 0.125 V
Sensitivity = 0.005 V/A
EngineeringCurrent = 25 A

日志如果只写:

text
原始电流 = 0.125 A

就已经失去语义真实性。

涉及测量值时至少核对:

text
RawValue
EngineeringValue
Conversion
ThresholdBasis
Aggregation
LoggedUnit

完整方法见 测量值语义

4. 一条关键结果最好能回答“怎么算出来的”

推荐追溯链:

text
Test / Task Id
→ Parameter Version
→ Device / Channel
→ Raw Evidence
→ Conversion
→ Engineering Data
→ Algorithm / Threshold
→ Event / Operator Action
→ Final Result

并不是所有项目都必须永久保存全链。

但如果某个结果用于:

  • 客户验收;
  • 质量追溯;
  • 故障分析;
  • 测试判定;
  • 安全联锁;

就应该能说明证据保留到哪一层。

5. Timestamp 先确定“谁的时间”

常见来源:

text
HostTime
DeviceTime
ExternalSystemTime
AcquisitionIndex

不要看到一个 DateTime.Now 就默认它是测量发生时间。

例如设备带自己的采样时间,而上位机晚 200 ms 收到数据:

text
DeviceTimestamp = 测量发生时间
HostReceiveTime = 上位机收到时间

两者都有价值,但语义不同。

对于高频数据,如果真实顺序比墙钟时间更重要,还应保留 sequence/index。

6. 保存失败的后果必须显式定义

“保存失败”也不是固定等于“停止测试”。

可以是:

text
Information
AlarmOnly
Advisory
InterlockFault

例如:

原始调试日志保存失败

可能是:

text
AlarmOnly
→ 当前测试继续
→ 提示维护人员

法规/质量要求规定测试结果必须落盘

可能是:

text
InterlockFault
→ 不允许把本轮标记为有效完成

后果必须来自业务要求,而不是由 IOException 自己决定。

详细语义见 行为与告警语义

7. 文件还是数据库:先看访问方式,不看“哪个更高级”

CSV / JSON / 二进制文件适合

  • 一次测试一份结果;
  • 查询简单;
  • 现场需要人工复制/查看;
  • 部署要简单;
  • 原始波形/大块数据天然是文件。

SQLite 适合

  • 单机应用;
  • 需要条件查询;
  • 数据关系不复杂;
  • 不想部署服务端数据库。

PostgreSQL / MySQL 等适合

  • 多客户端;
  • 集中查询;
  • 业务已有数据库平台;
  • 需要权限、事务或统一运维。

不要为了一个“历史列表”就自动引入服务端数据库。

8. Source of Truth:同一个参数不要四处都是权威值

例如一个最大电流:

text
XAML 默认值
ViewModel 常量
appsettings.json
数据库配置表
MES 下发
设备能力

如果都能改,迟早不一致。

需要明确:

text
DomainConstraint Owner
External Contract
Device Capability
User Override

正式范围变化参考 业务约束跨层传播

9. 配置数据需要区分“用户偏好”和“业务规则”

例如:

配置类型
窗口宽度UserPreference
曲线刷新间隔Display/Performance Setting
最大允许高压DomainConstraint / DeviceCapability
调试模式临时上限EngineeringOverride
MES 字段单位ExternalContract

这决定:

  • 是否需要版本;
  • 是否需要迁移;
  • 是否允许用户直接编辑;
  • 是否传播到外部系统和设备。

10. 写入策略:别让保存线程反过来拖死采集

需要回答:

text
WriteMode: immediate / batch / end-of-test
BufferCapacity:
Backpressure:
FlushPolicy:
StopPolicy:
FailureConsequence:

例如高频原始数据:

text
采集
→ bounded queue
→ batch writer
→ file

满队列时到底:

  • 阻塞采集;
  • 丢弃数据;
  • 降采样;
  • 报警;
  • 停止测试;

属于业务决策,不能由 ConcurrentQueue 默认行为代替。

资源生命周期详见 线程、设备会话与资源生命周期

11. 文件完整性:写成功和结果完整不是一回事

至少考虑:

  • 中途断电;
  • 软件异常退出;
  • 文件被占用;
  • 临时文件未 rename;
  • Flush 未完成;
  • 一次测试只写了一半;
  • 导出时读取到仍在写的文件。

根据重要性选择:

text
temp + atomic replace
append + record framing
transaction
checkpoint
end marker / completed flag

不要对普通调试日志过度设计事务;也不要让正式验收结果只靠“文件存在”判断完整。

12. Schema / 字段语义变化要考虑历史兼容

如果改变:

  • 字段名;
  • 数据类型;
  • 单位;
  • 枚举值;
  • JSON/XML schema;
  • CSV 列顺序;
  • 数据库字段;

先问:

text
旧数据要不要继续读?
旧配置要不要兼容?
旧版本软件是否会读新文件?
新版本是否要展示旧结果?
外部系统契约是否允许变化?

内部表示变化不等于外部格式必须变化

例如内部从分钟统一为秒:

text
Internal = seconds
Existing file/MES contract = minutes

完全可以通过边界转换保持兼容。

13. RegressionFix:数据问题以前正常就比较同一字段的全链

用户说:

text
以前导出的电流是对的,这版变成小数值了

先比较:

text
KnownGood Raw
→ Conversion
→ DTO/Model
→ Saved Field
→ Display/Export

再看最近 changed files。

优先找第一个语义差异,不要先把整个数据层重构。

14. 操作日志和诊断日志用途不同

OperationalLog

面向追溯:

text

何时
做了什么
参数是什么
结果是什么

DiagnosticDetail

面向定位:

text
底层命令
原始响应
异常类型
错误码
堆栈
session
时间线

操作员主界面可以只展示摘要,原始诊断仍应保留到维护日志。见 操作员界面与维护诊断分层

15. 新系统最小数据字典

text
Field
BusinessMeaning
Source
RawOrEngineering
Type
Unit
Precision
TimestampSource
Persistence
Export
Compatibility
Notes

示例:

text
ChargeCurrent
充电阶段工程电流
Scope CH2
Engineering
float
A
0.01
HostReceiveTime + SampleIndex
Result CSV
Yes
V1+
Raw voltage stored separately for diagnosis

不要只写“float current”。

16. 数据保存验证按风险选

V1

纯导出格式/列标题:

  • 生成一份文件;
  • 列名/格式正确;
  • 原业务数据不变。

V2

数据语义、配置、数据库、兼容:

  • known input → expected stored value;
  • 单位/Conversion;
  • roundtrip;
  • 旧配置/旧记录(若相关);
  • save failure path。

V3

保存后果影响测试流程:

  • 保存失败时是否继续/停止;
  • 流程状态和结果有效性;
  • stop 时 queue drain;
  • workflow smoke。

V4

Schema/外部契约/发布兼容变化:

  • migration;
  • old/new compatibility;
  • representative historical data;
  • external consumer acceptance。

17. 两个可直接复制的 Prompt

查一个字段现在怎么保存

text
$host-computer-dev
只做 Read-Only Trace。

字段/数值:
【填写】

请追踪:
Source → Raw/Engineering → Conversion → Model/DTO → Persistence/Export → Unit。
说明当前 timestamp 来源和最终保存位置。
不要修改代码、构建或分析整个数据库。

修改一个数据字段/规则

text
$host-computer-dev
这是一个已明确的数据修改。

CurrentBehavior:
RequestedBehavior:
NonGoals:

请先判断是否涉及:
- Measurement Semantics;
- DomainConstraint;
- Schema/Compatibility;
- External Contract。

只沿相关字段的数据链修改,不重构无关存储模块。
完成后按 V1–V4 选择 focused verification;如果旧数据兼容不相关,不要自动设计迁移。

18. 常见反模式

反模式后果
Raw 和工程量字段名混用日志/追溯失真
保存失败一律 Stop非关键日志故障阻断试验
所有配置都当 DomainConstraint小设置变成跨层重流程
内部单位变化机械修改外部格式破坏兼容
一次测试文件存在就算完整半文件被当有效结果
无界保存队列长稳内存增长
一个字段修改全数据库扫描小改成本失控
只保存最终判定、不保留关键证据现场无法复盘

下一步

一句话原则

先保证数据语义真实,再决定怎么存;保存失败的业务后果要显式定义,兼容只在实际相关时做。

别来无恙 · C# 上位机 AI 实战站 · 从零到交付 · QQ 群:1016188499