如何优化Progress 4GL大数据量WebSpeed页面的数据库访问速度?
兄弟,看完你的场景和代码,我一眼就瞅到问题核心了——每循环一次serial就全量遍历一遍mstr表,18万次循环意味着mstr被扫了18万次!这就是为什么serial循环越多总时长越爆炸,还有那些偶尔的1ms延迟累积起来拖垮总耗时的根本原因。结合你的索引情况,给你几个针对性的优化方案,每一个都能实打实把耗时砍下来:
1. 彻底重构嵌套查询逻辑,把“串行遍历”改成“关联查询”
你现在的逻辑绕了大弯:循环serial → 遍历所有mstr → 找对应det。完全反过来搞,先把符合条件的mstr一次性捞出来,再通过关联直接匹配serial和det,绝对能把IO次数砍到原来的零头:
DEFINE QUERY Mstr FOR mstr. DEFINE TEMP-TABLE tt_mstr NO-UNDO LIKE mstr INDEX nbr_idx IS PRIMARY UNIQUE FOR mstr_nbr. -- 先把所有状态为close/closed的mstr一次性加载到临时表,建唯一索引方便快速查找 OPEN QUERY Mstr FOR EACH mstr NO-LOCK WHERE Mstr_status = "close" OR Mstr_status = "closed". FOR EACH mstr USING QUERY Mstr: CREATE tt_mstr. BUFFER-COPY mstr TO tt_mstr. END. -- 现在遍历serial,直接通过det关联mstr,再也不用全扫mstr了 FOR EACH serial WHERE (serial_pallet = f_pallet AND serial_f_chr11 <> "BOX") OR (serial_key BEGINS f_pallet) NO-LOCK BREAK BY serial_pallet BY serial_parent BY serial__chr11 QUERY-TUNING(LOOKAHEAD CACHE-SIZE 65536 DEBUG EXTENDED): -- 直接关联det和临时表的mstr,一步到位统计数量 FOR EACH det NO-LOCK WHERE detmodel = serial_parent AND detlot = serial__chr11, FIRST tt_mstr NO-LOCK WHERE tt_mstr.mstr_nbr = detnbr: tinspected = tinspected + detqty. END. END.
2. 给det表加个复合索引,让关联查询飞起来
你现在的det表索引都是单字段或者主键的多字段,但你的查询条件是detmodel = serial_parent AND detlot = serial__chr11 AND detnbr = mstr_nbr,专门建一个匹配这个条件的复合索引:
CREATE INDEX det_model_lot_nbr ON det (detmodel, detlot, detnbr) ACTIVE;
这个索引能让数据库直接定位到符合条件的det记录,不用再扫表,速度至少提好几倍。
3. 删掉那个多余的REPOSITION操作,纯纯浪费IO
你在serial循环里做的reposition mstr to rowid roID完全没用——下一次循环你又会GET FIRST Mstr重新扫表,这个操作只会额外产生磁盘IO,累积起来也是一笔不小的开销,直接删掉就行。
4. 优化serial表的索引,搞定OR条件的性能问题
你的serial查询用了OR条件(serial_pallet = f_pallet AND serial_f_chr11 <> "BOX") OR (serial_key BEGINS f_pallet),OR很容易让索引失效,给你两个解决办法:
- 如果
serial_key begins f_pallet的场景占比不高,直接拆成两个独立的FOR EACH分别处理,避免OR带来的性能损耗 - 建一个覆盖索引,包含查询和排序需要的所有字段:
这个索引能覆盖你的WHERE条件和BREAK BY排序,数据库不用回表取数据,直接从索引就能拿到所有需要的字段,延迟会低很多。CREATE INDEX serial_pallet_parent_chr11 ON serial (serial_pallet, serial_parent, serial__chr11, serial_key, serial_f_chr11) ACTIVE;
5. 调大缓存参数,减少磁盘IO的偶尔延迟
你已经用了QUERY-TUNING(LOOKAHEAD CACHE-SIZE 32768),可以尝试把CACHE-SIZE调到65536甚至更大(只要内存够),让更多数据缓存到内存里,那些偶尔的1ms磁盘IO延迟就会大幅减少。
6. 去掉不必要的SCROLLING查询
你的Mstr查询用了scrolling,但你只是从头到尾遍历一遍,根本不需要维护游标位置,scrolling会额外消耗资源,直接改成普通查询就行:
DEFINE QUERY Mstr FOR mstr. -- 删掉scrolling
内容的提问来源于stack exchange,提问作者kushal bhatia

