20 KiB
电能质量 13 张表批量补数设计说明
1. 背景
tools/add-data 当前只有模块骨架和历史 SQL 文件 DATA_FLICKER.sql,尚未提供真实业务接口。
本次需求是在 add-data 模块中补齐一套“按时间区间批量生成电能质量数据并写入数据库”的能力,满足以下业务目标:
- 支持按时间区间补数,例如一天、一月。
- 支持时间戳步长选择:
1、3、5、10分钟。 - 支持单监测点和多监测点,前端可选择监测点 ID,默认单监测点。
- 支持批量写入,优先保证大区间补数时的效率。
- 同一主键数据已存在时跳过,不覆盖、不删除。
- 同步提供前端页面交互方案与参数展示规则。
2. 范围确认
根据当前 DATA_FLICKER.sql 内容,本次补数范围按 13 张表处理,而不是 14 张表:
data_flickerdata_flucdata_harmphasic_idata_harmphasic_vdata_harmpower_pdata_harmpower_qdata_harmpower_sdata_harmrate_idata_harmrate_vdata_idata_inharm_idata_pltdata_v
3. 已确认需求
本次设计基于以下已确认结论:
- 写入方式是“按时间戳步长生成整段数据”,不是定时常驻写库。
- 重复补数时采用“跳过已存在数据”策略。
- 前端方案需要和后端接口一起设计。
- 分表时间轴规则已确认:
data_flicker固定每10分钟写一组data_fluc固定每10分钟写一组data_plt固定每2小时写一组- 其余
10张表按前端选择的1、3、5、10分钟步长写入 - 所有时间点都按自然时间槽对齐,采用整点整分方式生成,不按传入开始时间顺延
- 展示字段需要覆盖:
电能质量参数名称相别是否合格最大值最小值平均值95%概率大值数据展示(保留小数)
- 数值展示默认保留
2位小数。 - 相别参照用户提供图片中的“相别”列。
4. 关键约束
4.1 主键约束
13 张表均以 LINEID + TIMEID + PHASIC_TYPE 作为主键,重复写入时必须避免主键冲突导致整批失败。
4.2 相别字段长度约束
PHASIC_TYPE 字段长度为 varchar(2)。因此前端展示中的相别值和数据库实际落库值不能简单等同:
- 页面展示可使用
T、ABC、AB/BC/CA - 落库时必须拆分为真实可存储的
PHASIC_TYPE
4.3 数据量约束
当时间区间为“一月”、步长为“1 分钟”、监测点为“多选”时,补数规模会非常大,不能采用单条插入或一次性全量加载入内存的方式。
4.4 现有仓库约束
- 当前仓库是后端工程,没有现成前端代码,本次只输出前端交互方案和接口契约。
- 默认不执行
mvn编译、打包、测试。 - 修改范围应尽量收敛在
tools/add-data模块内。
5. 方案选择
本次比较三种实现路径:
方案 A:同步接口直接写库
特点:
- 控制器接收参数后直接在请求线程中完成全部写库。
- 实现最简单。
问题:
- 大区间、多监测点时容易超时。
- 任务执行中断后难以定位进度。
- 前端体验差,无法明确看到当前执行状态。
结论:
不采用。
方案 B:异步任务 + JDBC 批量写入
特点:
- 请求只负责创建任务,后台异步执行。
- 任务状态可轮询。
- 批量写入时可按表、按批次提交。
优势:
- 更适合月级、多监测点补数。
- 可以精细控制批次大小。
- 当前数据源连接串已开启
rewriteBatchedStatements=true,适合批处理。
结论:
采用该方案。
方案 C:只生成 SQL 文件,人工执行
特点:
- 后端只生成 SQL 脚本,不直接写库。
问题:
- 需要人工执行,流程割裂。
- 不符合“前端选择后直接补数”的目标。
结论:
不采用。
6. 总体设计
6.1 设计目标
在 tools/add-data 中新增一套“批量补数任务”能力,支持:
- 前端提交补数参数
- 后端预估本次写入规模
- 后端异步生成数据并按表批量写入
- 前端轮询任务状态
- 前端获取参数展示规则
6.2 模块边界
本次能力只落在 tools/add-data,不向 system、user、detection 扩散业务逻辑。
如需监测点列表,首版不假设存在基础监测点表,也不新增点位管理能力,直接由前端传入选中的 lineIds。
6.3 接口拆分
建议把“任务管理”和“参数模板展示”分成两类接口:
- 补数任务接口:负责预估、创建、状态查询
- 模板展示接口:负责返回图片对应的参数展示规则
7. 数据模型与相别规则
7.1 展示相别与落库相别分离
前端展示相别来自用户图片中的“相别”列,但落库时需要展开成真正的 PHASIC_TYPE 值。
建议在模板中同时维护:
phaseDisplay:前端展示值phaseCodes:落库使用的真实相别集合
7.2 相别展开规则
建议默认规则如下:
T->["T"]ABC->["A", "B", "C"]AB/BC/CA->["AB", "BC", "CA"]
这套规则同时用于:
- 决定每个参数需要展开多少条写库数据
- 决定前端参数表如何显示相别列
7.3 参数模板职责
参数模板不直接等于数据库表结构,而是承担以下职责:
- 描述前端展示行
- 绑定该参数对应的数据表
- 描述展示相别和落库相别
- 约定是否展示“是否合格”
- 约定最大值、最小值、平均值、95%概率大值的展示逻辑
- 约定保留小数位数,默认
2
8. 后端接口设计
8.1 预估接口
接口:
POST /addData/task/preview
作用:
- 根据
lineIds、时间区间、时间戳步长,返回本次补数的预估规模
入参:
lineIds:监测点 ID 列表startTime:开始时间endTime:结束时间intervalMinutes:1、3、5、10
返回内容:
- 时间点数量
- 监测点数量
- 每张表预估写入条数
- 总预估条数
说明:
- 预估逻辑必须按分表时间轴分别计算。
intervalMinutes只影响data_harmphasic_i、data_harmphasic_v、data_harmpower_p、data_harmpower_q、data_harmpower_s、data_harmrate_i、data_harmrate_v、data_i、data_inharm_i、data_v这10张表。data_flicker、data_fluc固定按10分钟时间槽计算。data_plt固定按2小时时间槽计算。
8.2 创建任务接口
接口:
POST /addData/task/create
作用:
- 创建一个批量补数任务,并立即进入后台执行
入参:
lineIdsstartTimeendTimeintervalMinutes
返回内容:
taskId- 初始状态
说明:
- 前端默认提交单个
lineId - 多监测点时前端直接提交多个
lineIds - 不单独拆分“单点接口”和“多点接口”
intervalMinutes仅作为10张基础实时类表的生成步长- 固定频率表仍按各自时间轴生成,不跟随
intervalMinutes
8.3 任务状态接口
接口:
GET /addData/task/status/{taskId}
作用:
- 供前端轮询当前任务执行状态
返回内容:
- 任务状态:
WAITING、RUNNING、SUCCESS、FAILED - 当前执行表名
- 当前批次信息
- 已写入条数
- 已跳过条数
- 失败条数
- 失败原因
- 开始时间、结束时间
8.4 参数模板接口
接口:
GET /addData/template/list
作用:
- 返回前端页面参数规则表所需的静态配置
返回内容:
- 电能质量参数名称
- 相别展示值
- 是否展示“是否合格”
- 最大值规则
- 最小值规则
- 平均值规则
- 95%概率大值规则
- 保留小数位数
9. 后端分层设计
9.1 Controller 层
建议新增两个控制器:
AddDataTaskController- 补数任务相关接口
AddDataTemplateController- 参数模板查询接口
9.2 Service 层
建议拆分为:
AddDataTaskService- 创建任务
- 状态查询
- 预估规模
AddDataTemplateService- 返回前端参数模板
9.3 Component 层
建议新增以下组件:
AddDataTaskExecutor- 负责异步执行任务
AddDataBatchWriter- 负责按表批量写入
AddDataValueGenerator- 负责根据模板生成每条记录的值
AddDataTaskStatusHolder- 首版用内存保存任务状态
AddDataTemplateRegistry- 持有参数模板与相别映射
9.4 数据访问层
本次不建议为 13 张表分别创建超长 MyBatis XML 批量插入语句。
原因如下:
- 宽表字段极多,XML 可维护性差。
- 13 张表结构差异大,重复代码很多。
- 本次更偏工具型批处理写数,不适合以业务实体方式逐表建模。
建议采用:
JdbcTemplatePreparedStatementbatchUpdate
在写入 SQL 上统一使用:
INSERT IGNORE
以满足“跳过已存在数据”的业务要求。
10. 批量写入策略
10.1 总体原则
批量写入必须满足以下原则:
- 不先查存在再插入
- 不整段数据一次性全部放入内存
- 按表、按批次逐步提交
- 主键冲突自动跳过
10.2 跳过已存在数据
采用 INSERT IGNORE 而不是以下策略:
- 不采用“先查后写”,避免额外查询放大数据库压力
- 不采用“覆盖更新”,与已确认需求不符
- 不采用“先删后写”,避免误删
10.3 流式生成
建议按如下顺序流式生成:
- 先遍历时间点
- 再遍历监测点
- 再按模板展开相别
- 最后路由到对应表的批缓存
达到批次阈值后立即落库并清空当前缓存。
10.4 分批阈值
建议根据表宽度分层设置批次大小:
- 窄表:
500 ~ 1000行/批 - 宽表:
100 ~ 200行/批
其中以下表建议视为宽表:
data_harmphasic_idata_harmphasic_vdata_harmpower_pdata_harmpower_qdata_harmpower_sdata_harmrate_idata_harmrate_vdata_idata_inharm_idata_v
10.5 任务统计
任务执行过程中需累计以下统计值:
insertedCountskippedCountfailedCount
其中:
insertedCount表示本次真正插入成功的行数skippedCount表示因主键重复被忽略的行数failedCount表示非主键冲突导致的失败数量
11. 数据生成策略
11.1 首版原则
首版不引入复杂公式配置,不让前端传计算表达式。数据生成规则由后端内置。
11.2 分表时间轴规则
本次补数不采用“全部表共用同一时间轴”的方式,而是拆成三类时间轴:
- 固定
10分钟时间轴 - 固定
2小时时间轴 - 用户步长时间轴
具体规则如下:
data_flicker- 固定每
10分钟一组 - 按自然时间槽对齐,例如
10:00、10:10、10:20
- 固定每
data_fluc- 固定每
10分钟一组 - 按自然时间槽对齐
- 固定每
data_plt- 固定每
2小时一组 - 按自然时间槽对齐,例如
00:00、02:00、04:00
- 固定每
- 其余
10张表- 按前端传入的
intervalMinutes生成 - 允许值仅为
1、3、5、10 - 同样按自然时间槽对齐
- 按前端传入的
如果前端传入 startTime=10:07:
10分钟表应从10:10开始2小时表应从12:00或下一个符合槽位的时刻开始- 用户步长表应从不小于
startTime的下一个对应槽位开始
11.3 统一生成方式
建议采用“基础状态生成 + 派生字段回填 + 分表时间轴裁切”的方式:
- 先按
(lineId, timeId)生成基础电气状态 - 再从基础状态派生电压、电流、谐波、功率、闪变
- 最后按各表自己的时间轴决定是否落库
统一原则如下:
- 同一时间点的 13 张表数据必须同源,不允许各表独立随机
- 主值字段按基准值和受控扰动生成
- 最大值字段不小于主值
- 最小值字段不大于主值
95%概率大值对应CP95字段- 宽表中的谐波分量和派生列按统一规则回填
- 同一输入参数应尽量生成可复现的结果,不建议使用完全无约束随机数
11.4 逐表生成规律
11.4.1 基础源表
data_v 作为电压源表,优先生成:
- 先生成
FREQ - 再生成
RMS - 再派生
RMSAB、RMSBC、RMSCA - 再派生
VU_DEV、VL_DEV、FREQ_DEV - 再派生
V_POS、V_NEG、V_ZERO、V_UNBALANCE - 最后生成
V_1 ~ V_50 V_THD由V_2 ~ V_50与V_1计算
data_i 作为电流源表,与 data_v 保持同源:
- 先生成
RMS - 再生成
I_POS、I_NEG、I_ZERO、I_UNBALANCE - 再生成
I_1 ~ I_50 I_THD由I_2 ~ I_50与I_1计算
对这两张源表:
RMS_MAX、RMS_MIN、RMS_CP95FREQ_MAX、FREQ_MIN、FREQ_CP95V_THD_MAX、V_THD_MIN、V_THD_CP95I_THD_MAX、I_THD_MIN、I_THD_CP95
均必须由主值派生,不单独随机。
11.4.2 谐波幅值表
data_harmphasic_v:
- 直接复用
data_v中的V_1 ~ V_50 - 各次谐波的
MAX、MIN、CP95与data_v同源派生
data_harmphasic_i:
- 直接复用
data_i中的I_1 ~ I_50 - 各次谐波的
MAX、MIN、CP95与data_i同源派生
11.4.3 谐波占比表
data_harmrate_v:
- 从
data_harmphasic_v派生 - 建议按
V_n / V_1 * 100计算V_1 ~ V_50对应占比值 MAX、MIN、CP95也按同样比例换算
data_harmrate_i:
- 从
data_harmphasic_i派生 - 建议按
I_n / I_1 * 100计算I_1 ~ I_50对应占比值 MAX、MIN、CP95也按同样比例换算
11.4.4 间谐波电流表
data_inharm_i:
- 作为电流间谐波表生成
- 各阶值应明显小于对应整数次谐波值
- 建议按“整数次谐波值乘以小比例系数”生成
MAX、MIN、CP95继续由主值派生
11.4.5 谐波功率表
data_harmpower_p:
- 从电压谐波和电流谐波联合派生
P_1 ~ P_50建议按电压谐波、电流谐波和相位关系计算P为各次分量汇总PF、DF由功率关系派生
data_harmpower_q:
- 与
data_harmpower_p同源 Q_1 ~ Q_50按无功功率关系派生Q为各次分量汇总
data_harmpower_s:
- 与
data_harmpower_p、data_harmpower_q同源 S_1 ~ S_50建议由P_n与Q_n派生S为各次分量汇总
这三张表中的 MAX、MIN、CP95 也必须基于对应主值派生。
11.4.6 闪变与波动表
data_flicker:
- 固定
10分钟时间轴 - 生成
FLUC、PST、PLT FLUC作为波动主值PST从FLUC派生PLT作为长时闪变指标生成,但落库节奏仍为10分钟
data_fluc:
- 固定
10分钟时间轴 - 生成
FLUC、FLUCCF - 与
data_flicker同源 FLUCCF作为FLUC的修正或归一化结果生成
data_plt:
- 固定
2小时时间轴 - 只写
PLT PLT来源应与data_flicker中的PLT同源- 但只在
2小时槽位落表
11.5 前端展示字段映射
由于表结构中没有独立 AVG 字段,前端“平均值”首版建议直接取各参数主值字段。
例如:
- 电压类参数取
RMS、V_THD、FREQ - 电流类参数取
RMS、I_THD - 闪变类参数取
FLUC、PST、PLT - 功率类参数取
P、Q、S
前端展示中的:
最大值-> 对应*_MAX最小值-> 对应*_MIN95%概率大值-> 对应*_CP95平均值-> 对应主值字段
11.6 质量标识
QUALITYFLAG 首版建议统一使用固定有效值,例如 1。
前端“是否合格”不直接读取数据库 QUALITYFLAG 的原始含义,而是走模板展示规则,避免把数据生成逻辑和展示文案硬耦合。
12. 前端页面交互方案
12.1 页面结构
建议页面分为两个区域:
- 补数任务区
- 参数规则展示区
12.2 补数任务区
表单项建议如下:
- 监测点选择模式:
单点/多点 - 监测点 ID 选择框
- 开始时间
- 结束时间
- 时间戳步长:
1、3、5、10分钟 - 预计写入量按钮
- 开始补数按钮
交互说明:
- 默认单监测点
- 多监测点时切换为多选
- 时间戳步长只影响
10张基础实时类表 data_flicker、data_fluc固定按10分钟槽位写入data_plt固定按2小时槽位写入- 前端先调用预估接口,展示预计写入规模
- 用户确认后再调用创建任务接口
12.3 任务状态展示
前端创建任务后轮询状态接口,建议展示:
- 当前状态
- 当前表名
- 已写入数量
- 已跳过数量
- 失败数量
- 失败原因
- 开始时间
- 结束时间
12.4 参数规则展示区
参数规则表按用户提供图片组织,至少展示以下列:
电能质量参数名称相别显示最大值最小值平均值95%概率大值是否合格数据展示(保留小数)
其中:
- 相别列使用
phaseDisplay - 所有数值默认保留
2位小数 - 该表展示的是模板规则,不是实时数据库统计结果
13. 文件结构建议
建议在 tools/add-data 下按现有仓库风格扩展:
tools/add-data/src/main/java/com/njcn/gather/tool/adddata/
├── controller
│ ├── AddDataTaskController.java
│ └── AddDataTemplateController.java
├── service
│ ├── AddDataTaskService.java
│ ├── AddDataTemplateService.java
│ └── impl
│ ├── AddDataTaskServiceImpl.java
│ └── AddDataTemplateServiceImpl.java
├── component
│ ├── AddDataTaskExecutor.java
│ ├── AddDataBatchWriter.java
│ ├── AddDataValueGenerator.java
│ ├── AddDataTaskStatusHolder.java
│ └── AddDataTemplateRegistry.java
└── pojo
├── param
└── vo
如参数模板需落成资源文件,建议放在:
tools/add-data/src/main/resources/template/add-data-parameter-template.json
14. 非目标
本次不包含以下内容:
- 不新增监测点基础信息管理能力
- 不新增监测点字典表
- 不新增数据库迁移框架
- 不在
system或user模块中扩展通用任务中心 - 不实现真实前端页面代码
- 不做覆盖更新或先删后写逻辑
15. 风险与取舍
15.1 内存态任务状态的风险
首版如果使用内存保存任务状态:
- 服务重启后任务状态会丢失
- 适合当前工具型场景
- 不适合后续演进为长期审计能力
当前取舍:
- 首版接受该限制
- 如果后续需要审计与追踪,再补任务表
15.2 模板与真实表字段映射的风险
用户图片中的参数项比“13 张表名”更偏业务视角,实际落库需要一层参数模板到表结构的映射。
当前取舍:
- 首版把模板规则集中维护在
AddDataTemplateRegistry - 不在前端直接拼接数据库字段名
15.3 大批量写入的数据库压力
多监测点、长区间、1 分钟步长时数据库压力会很大。
当前取舍:
- 采用预估接口提前提示规模
- 控制批次大小
- 使用异步执行与
INSERT IGNORE
16. 验证方式
本次设计和后续实现默认不执行 mvn,验证方式以静态检查和链路闭合检查为主。
16.1 设计验证
确认以下设计点闭合:
- 13 张表范围明确
- 相别展示与落库规则明确
- 重复数据处理策略明确
- 前后端接口契约明确
- 批量写入策略明确
16.2 实现后验证
后续实现时重点检查:
- 入参校验是否覆盖时间区间、步长、监测点 ID 列表
- 预估条数计算是否正确
- SQL 是否统一使用
INSERT IGNORE - 批次是否按宽表和窄表区分
- 重复补数时是否正确累加
skippedCount - 参数模板返回是否与图片字段一致
17. 结论
本次采用“异步任务 + JDBC 批量写入 + 参数模板展示接口”的实现方案,在 tools/add-data 模块内完成电能质量 13 张表的批量补数能力。
该方案兼顾以下目标:
- 支持单监测点和多监测点
- 支持日级、月级区间
- 支持 1/3/5/10 分钟时间戳步长
- 支持重复补数时跳过已存在数据
- 支持前端按图片规则展示参数和相别
- 在当前仓库约束下把改动范围控制在最小必要集合