MES报表WORKER_NUM口径反了,工位利用率被除成零(2026-09-14)
不要急着改前端,先拿 SQL 把 572 万行逐行比对钉死——老表的 WORKER_NUM 就是真实人数,上一版却按 ×10 把它除成了 0。
2026-09-14 这天挺满。上午刚把 Hyperliquid testnet 的 drift 3341.32% 告警挂出去,下午就被叫去修一个 MES 报表:工位利用率、出勤时间、有效工时,显示得全不对。表面看是前端渲染有问题,实际一查,口径从根上就反了。
一、问题现象:所有指标都长得不对劲接下活的时候,用户给的是 100.64.0.2:3306 上 m3_ai_data 库的 work_load_0521 表,里面有示例数据。前端报表展出来的工位利用率、出勤时间、有效工时,没一个看着合理。当时我没急着动逻辑,先让脚本把表的概况拉出来。
这一拉就发现问题不小:
AREA 一共 14 个,前端只认 5 个;
MAIN_AREA 分布是 TST1 约 450 万行、TST2 约 77 万行、TST3/TST4 各约 22 万行;
WORKER_NUM 的值是 '0'~'7',看着像真实人数,但我们上一 ...
v1.25 全量验证跑完 50 个回测并逐一核查页面数据源(2026-06-18)
验证不是"看起来没报错",是把每一格都点开看过
v1.25 的代码前一天已经写完、入库、冒烟。但"写完"和"验证完"之间,隔着一段必须走的流程:换一个干净进程、把回测跑满、把每个页面的数据源挨个查一遍。
这天做的就是把这段流程走完。全量验证,一个页面都不跳。
先换一个干净的进程验证的第一原则是别在旧的进程上验。
杀掉旧进程(417088、416872),重启 4 个新实例,主进程 PID 402864 加 3 个辅助进程,port 8501 返回 HTTP 200。
为什么非要重启?因为旧进程里可能还残留着改代码之前加载的模块。**要验的是"现在这份代码",不是"过去某个时刻加载过的代码"**——不重启,验的可能是一份已经不存在的版本。
104 秒,50 个版本backtest_runner.py 跑完,耗时 104s,exit 0,50 个版本回测完成,结果写入 bt_cf_summary 和 bt_cf_trades,最新 run_at 是 2026-06-18 10:44:44。 ...
TVL看板图表空白,写入端向不存在的protocol列写数据导致全丢(2026-06-15)
数据"消失"的时候,先看它是被删了,还是根本没写进去
TVL 看板某天开始是空的。不是加载慢,是图表直接报错,一张干干净净的空白。
这天把这块看板修回来。
一块空的图页面 pages/1_tvl_rank.py 里的 Plotly 柱状图,x 轴取的是 protocol 字段:
1px.bar(x='protocol')
它读到的是一个空列,于是图表报错、数据全丢。
前端报错看着像渲染问题,但真正的疑点应该往后推一步:数据是什么时候没的?是同步进来的数据本来就空,还是本来有、后来被写没了?
根因:往一个不存在的列里写查下来,问题在写入端,而且比想象中更基础。
tvl_rank 表原本就没有 protocol 列。而 save_tvl_rank 在做 INSERT 的时候,把协议名写进了这个不存在的列——结果数据全丢。
同时,页面又反过来用 px.bar(x='protocol') 去引用这个空列,于是一起报错。
这条链子很典型:写入端写了个不存在的目标,读取端读了个空的结果,两头各自沉默,直到图表上什么都看不见,才被人发现。中 ...
车间工时看板接入 MySQL 工时秒和人秒单位易错(2026-05-14)
需求很简单:让工时自己说话,别再靠人抄
车间里的工时数据是有的——机器一直在采,落在 MySQL 里。问题是没人看。数据躺在表里,要问产量就得有人去查、去汇总、去做表。信息在,但不在需要它的人眼前。
这块看板就是为了把这句话反过来:数据在哪儿产生,就在哪儿显示。
先看数据长什么样第一步永远是看表结构,而不是先想界面。
表是 work_load,在一台早期的 MySQL 上(100.64.0.2:3306,库叫 m3_ai_data)。字段不复杂:
字段
含义
START_TIME / END_TIME
一段工作的起止
WORKER_NUM
工位编号
WORKTIME
工时,单位秒
WORKLOAD
工作量,单位人·秒
AREA / MAIN_AREA
区域 / 主区域
两个细节后来证明很关键:工时是秒不是分钟,**工作量是"人·秒"**。也就是说,同是一小时,两个人干出来的是一个人的两倍——这一条决定了后面所有图表的口径。
还有一点,这几个字段都是 varchar。数值存成字符串,意味着不能在 SQL ...