Files
Neo-ZQYY/docs/audit/changes/2026-05-04__wave1_t2_scd2_view_unify.md
Neo b0340349bd feat(etl): cfg_* 视图入口统一 + NULL 兼容 + 3 处 _load_* 历史 Bug (W1-T2 / P0-1)
Wave 1 Day 3 沙箱配置参数切片。

DB 迁移 (20260504__cfg_views_null_compatible.sql):
- 4 个 v_cfg_* 视图 WHERE 加 NULL 兼容
  (effective_to IS NULL OR effective_to >= ...)
- 顺手清理 v_cfg_assistant_level_price / v_cfg_performance_tier
  WHERE 重复一次的 bug
- 测试库已执行,4 校验 PASS

ETL 代码 (4 处 SQL):
- base_index_task.py: FROM dws.cfg_index_parameters -> app.v_cfg_index_parameters
- base_dws_task.py 3 处 _load_* (performance_tier / level_price / bonus_rules)
  改 FROM app.v_cfg_*,顺手修历史 Bug:原 SQL 不带 effective_from/to WHERE

效果:
- 修复视图 NULL 行被过滤问题(SPI 27 行原本读到 0)
- 沙箱模式回放历史日期时,参数自动按 sandbox_date 切片
- _load_* 直接得到当前生效行(原 12/9 行历史 Python 挑)

参考:
- docs/audit/changes/2026-05-04__wave1_t2_scd2_view_unify.md
- docs/database/changes/2026-05-04__cfg_views_null_compatible.md
2026-05-04 08:10:57 +08:00

5.0 KiB

Wave 1 W1-T2 — SCD2 视图入口统一 + 4 视图 NULL 兼容 + 3 处 load*

字段
日期 2026-05-04
Wave 1 / Day 3
范围 P0-1 沙箱配置参数切片(SCD2 视图入口统一)+ F-1 副发现 base_dws_task 3 处 load* 历史 Bug
文件改动 1 迁移 + 2 ETL py + 1 db 文档
验证 测试库 4 视图行数与裸表等价 WHERE 全部一致

一、改动总览

1. DB 视图修复(迁移)

文件:db/etl_feiqiu/migrations/20260504__cfg_views_null_compatible.sql

修 4 个 app.v_cfg_* 视图:

  • v_cfg_index_parameters
  • v_cfg_assistant_level_price
  • v_cfg_performance_tier
  • v_cfg_bonus_rules

WHERE 从 effective_to >= app.business_date_now() 改为 (effective_to IS NULL OR effective_to >= app.business_date_now()), 顺手清理 2 个视图重复 WHERE bug。

2. ETL 代码改造(4 处 SQL)

# 文件 改动
1 tasks/dws/index/base_index_task.py:335-342 FROM dws.cfg_index_parameters + 显式 effective_from/to WHERE → FROM app.v_cfg_index_parameters 移除 WHERE
2 tasks/dws/base_dws_task.py:543-552 _load_performance_tiers FROM dws.cfg_performance_tierFROM app.v_cfg_performance_tier(并修复历史 Bug:原 SQL 不带 effective_from/to WHERE,把全部历史区间拉给 Python 挑)
3 tasks/dws/base_dws_task.py:556-567 _load_level_prices 同上,v_cfg_assistant_level_price
4 tasks/dws/base_dws_task.py:569-581 _load_bonus_rules 同上,v_cfg_bonus_rules

二、为什么这么改(F-1 调研结论回顾)

Neo 在 P0-1 反馈提出"沙箱机制下应该有每天的参数快照吗?"。F-1 调研结论:

  • 不需要每日快照(成本高、冗余)
  • SCD2 区间已存在(4 张 cfg 表已有 effective_from / effective_to)
  • 核心裂缝:P20 视图层已加业务日上界,但 ETL 任务直读 dws.cfg_* 裸表绕过视图 + 视图本身有 NULL 兼容 bug
  • 修复:让所有读取入口走视图(0.5 天工作量)

三、行为对照

场景 修改前 修改后
live 模式查 SPI 参数 27 行(原直读裸表带 WHERE) 27 行(走视图)
视图直接查 SPI 参数 0 行(NULL 兼容 Bug) 27 行
sandbox 切到 2026-03-01 查 SPI 仍是 live 27 行(代码绕过视图) 27 行(视图按 sandbox_date 切片)
sandbox 切到历史日期(假设有更早版本) 取不到历史版本 视图按 sandbox_date 取当时生效行
_load_performance_tiers 12 行全部历史(Python 挑) 5 行(当前生效)
_load_bonus_rules 9 行全部历史 3 行(当前生效)

四、验证(测试库)

测试库已执行迁移,4 校验全部 PASS:

  • view SPI count = 27,等价裸表 WHERE = 27
  • sandbox 2026-03-01 SPI count = 27
  • v_cfg_assistant_level_price: view 5 / equiv 5 / total 5
  • v_cfg_performance_tier: view 5 / equiv 5 / total 12
  • v_cfg_bonus_rules: view 3 / equiv 3 / total 9

详细 SQL 见 docs/database/changes/2026-05-04__cfg_views_null_compatible.md §五。

五、风险与回滚

风险 回滚
视图 ALTER 低 — CREATE OR REPLACE VIEW 原子操作 重新执行 20260502 迁移的 4 视图 CREATE OR REPLACE 部分
ETL SQL 改造 低 — 视图返回字段 / 类型与裸表 WHERE 等价 git revert
性能 视图复杂度未变(只多 1 个 NULL 判断),性能影响可忽略
历史 Bug 修复(3 处 load*) — 修复前 Python 挑历史区间是低效但正确,修复后视图直接给当前生效行 git revert(回到全量挑)

六、未覆盖 / 后续 Wave

  • 单测覆盖留 Wave 2(tests/test_cfg_views_sandbox.py,带 sandbox_date 切片用例)
  • P20 SPEC §1.4 / §3.5 / §5.6 / AC14-15 / §11.2 / T16-T17 patch 文字落地留 Wave 5(F-1 报告 §六已列出建议)
  • 生产库执行迁移留 Wave 5(P11 上线门槛达标后由 Neo 手动执行)

七、commit 建议消息

feat(etl): cfg_* 视图入口统一 + NULL 兼容 + 3 处 _load_* 历史 Bug (W1-T2 / P0-1)

Wave 1 Day 3 沙箱配置参数切片。

DB 迁移 (20260504__cfg_views_null_compatible.sql):
- 4 个 v_cfg_* 视图 WHERE 加 NULL 兼容
  (effective_to IS NULL OR effective_to >= ...)
- 顺手清理 v_cfg_assistant_level_price / v_cfg_performance_tier
  WHERE 重复一次的 bug
- 测试库已执行,4 校验 PASS

ETL 代码 (4 处 SQL):
- base_index_task.py: FROM dws.cfg_index_parameters → app.v_cfg_index_parameters
- base_dws_task.py 3 处 _load_* (performance_tier / level_price / bonus_rules)
  改 FROM app.v_cfg_*,顺手修历史 Bug:原 SQL 不带 effective_from/to WHERE

效果:
- 修复视图 NULL 行被过滤问题(SPI 27 行原本读到 0)
- 沙箱模式回放历史日期时,参数自动按 sandbox_date 切片
- _load_* 直接得到当前生效行(原 12/9 行历史 Python 挑)

参考:
- docs/audit/changes/2026-05-04__wave1_t2_scd2_view_unify.md
- docs/database/changes/2026-05-04__cfg_views_null_compatible.md