闲人闲谈PS之四十三——标准程序的陷阱

文章讲述了在项目制生产中遇到的标准报表效率问题,尤其是使用标准程序KOB1N的陷阱。由于默认的数据限制和全字段需求导致的内存问题,使得原本看似高效的解决方案在大量数据时变得低效。最终,通过回归原始的存表法和定制化处理解决了问题,强调了在开发功能验证时需充分考虑实际业务数据的考验。
摘要由CSDN通过智能技术生成

惯例闲话:7月,闲人家乡的水蜜桃成熟了,闲人很喜欢吃桃子,可惜经常出门在外,经常错过了水果最好的季节,这次委托家人邮寄了几箱,果然还是家乡的桃子好吃。回顾这几年,错过了不仅仅是水果,孩子的教育、成长,都是有很大的缺位。
做顾问到了这个年纪,也确实是要考虑家庭和事业均衡的时候了。PLM项目还有2-3个月,是差不多该做出决定了。

闲话到此为止,这次聊聊标准报表的陷阱!

项目生产工单成本和入库统计

项目制生产常见需求,统计某个项目在某个区间内投入和产出。
索引条件通常有
1、项目
2、WBS
3、科目
4、日期区间
财务报表带上时间区间的,往往就意味着 附带效率问题。而在项目型业务中,这种效率问题更为突出,通常会按整个项目全生命周期来查询累计,这种必然会引起报表效率问题。
在这里插入图片描述
在这里插入图片描述

解决效率问题,无外乎以下几种方法:
1、存表法
1)明确数据的汇总级别,存在项目制业务的,通常按项目、WBS作为汇总级别,常规业务则颗粒度细一点,按工单。可作为项目报表的下级钻取;
2)期末数据保存自定义表中,作为下一期期初数据,累加;
3)下一期数据仅查询期间内,通常为一个自然月为期间。
2、BW,本质也是存表;
3、调用标准程序法,这是近些年,闲人在项目上遇到的某个财务顾问的创新,直接调用KOB1N,CJI3N等。

前台选择条件如下
在这里插入图片描述

代码样例如下:

"获取ALV内容并且不显示ALV
CL_SALV_BS_RUNTIME_INFO=>SET( EXPORTING DISPLAY = ABAP_FALSE
METADATA = ABAP_FALSE
DATA = ABAP_TRUE ).

IF RT_AUFNR IS NOT INITIAL.
SET PARAMETER ID ‘CAC’ FIELD ‘CSCE’.
SUBMIT RKAEP000 WITH P_KOKRS = ‘CSCE’
WITH AUFNR IN RT_AUFNR "订单号
WITH R_BUDAT IN RT_BUDAT "过账日期
WITH P_HANA = ‘X’ "加速选择
WITH P_TREE = ‘’ "层次显示
WITH P_IMOUT = ‘’ "从完成清单开始
WITH P_GROBJ = ‘’ "组对象
WITH P_TCODE = ‘KOB1’
EXPORTING LIST TO MEMORY AND RETURN.
TRY.
"从内存中获取ALV内表数据
CL_SALV_BS_RUNTIME_INFO=>GET_DATA_REF( IMPORTING R_DATA = LR_KOB1N_DATA ).
ASSIGN LR_KOB1N_DATA->TO <LT_KOB1N_DATA>.

   IF <LT_KOB1N_DATA> IS ASSIGNED.
     "处理数据
     LOOP AT <LT_KOB1N_DATA> ASSIGNING FIELD-SYMBOL(<LFS_KOB1N_DATA>).
       CLEAR:LS_KOB1N_DATA.
       MOVE-CORRESPONDING <LFS_KOB1N_DATA> TO LS_KOB1N_DATA.
       COLLECT LS_KOB1N_DATA INTO LT_KOB1N_DATA.
     ENDLOOP.
     "以订单为维度汇总
     "以成本要素KSTAR 为条件获取:累计入库金额、当期入库金额、累计生产成本
     WITH +KOB1N_SUM AS (
          SELECT
                 DATA~AUFNR,     "订单
                 DATA~RWAER,     "报表货币
            CASE WHEN DATA~KSTAR = '5011999910'
                  AND DATA~GJAHR = @P_GJAHR
                  AND SUBSTRING( DATA~PERIO,2,2 ) = @P_MONAT
                 THEN SUM( DATA~WRGBTR )
                 END AS ZXXX2,   "累计入库金额
            CASE WHEN DATA~KSTAR = '5011999910'
                  AND DATA~GJAHR = @P_GJAHR
                  AND SUBSTRING( DATA~PERIO,2,2 ) = @P_MONAT
                 THEN SUM( DATA~WRGBTR )
                 END AS ZXXX3,   "当期入库金额
            CASE WHEN DATA~KSTAR <> '5011999910'
                  AND SUBSTRING( DATA~KSTAR,1,3 ) <> '998'
                  AND DATA~GJAHR = @P_GJAHR
                  AND SUBSTRING( DATA~PERIO,2,2 ) = @P_MONAT
                 THEN SUM( DATA~WRGBTR )
                 END AS ZXXX1    "累计生产成本
            FROM @LT_KOB1N_DATA AS DATA
            GROUP BY DATA~BUKRS,DATA~AUFNR,DATA~RWAER,DATA~KSTAR,DATA~GJAHR,DATA~PERIO )
     SELECT
            DATA~AUFNR,     "订单
            DATA~RWAER,     "报表货币
            SUM( DATA~ZXXX1 ) AS ZXXX1,   "累计生产成本
            SUM( DATA~ZXXX2 ) AS ZXXX2,   "累计入库金额
            SUM( DATA~ZXXX3 ) AS ZXXX3    "当期入库金额
       FROM +KOB1N_SUM AS DATA
       GROUP BY DATA~AUFNR,DATA~RWAER
     INTO TABLE @DATA(LT_KOB1N_SUM).
     SORT LT_KOB1N_SUM BY AUFNR.
   ENDIF.
 CATCH CX_SALV_BS_SC_RUNTIME_INFO.
   MESSAGE `无法获取事务码:KOB1N 的数据` TYPE 'E'.

ENDTRY.
ENDIF.

本文也是着重解构第三种方案的陷阱。

KOB1N的效率陷阱

从一般的思维角度,标准程序确实比自开发程序效率要高很多,这也是闲人的惯性思维,在多数情况,这个也是成立的。
已本案例为例,
在集成测试环节,前台测试了KOB1N和写逻辑从AUFM表中获取项目工单的投入和产出财务凭证数据。注意,闲人这里用前台测试,这个关键字眼,也恰恰这一点,被闲人和项目组同事忽略了,导致买下了一个效率的巨坑。
刚开始测试结果喜人:KOB1N的效率在15秒之内就可以读出数,而语句取AUFM时间大概在2分钟左右。项目组也毫不犹豫选择了这个“创新的方法”。

上线后1年多,财务反馈说报表出来数据异常
部分项目有入库数量没有入库金额。经过DEBUG发现

在这里插入图片描述原来在最大获取数据条目数据限制了5000,这也是为啥之前很长时间没有发现效率问题所在的直接原因,系统每次最大获取5000条数据,自然不会有“问题”。

在这里插入图片描述对标准代码做隐式增强,默认最大数

在这里插入图片描述当然结果可想而知,大概率dump

在这里插入图片描述然后按常规手法,用存表法来做,结果还是dump——很显然,每个月的生产量不一样,高峰期月数据量大,但个月也显然会内存溢出。所以,到这里,基本上就宣判了这个创新方法的“死刑”。

但是闲人不甘心,想不明白,为啥前台可以把当月的数据读出来,后台引用却不行。
直到前台操作,放出全量字段,就出现了一样的效果

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

再回到程序调用,果然不出所料,默认全量字段244个字段,内存够才怪!!!根本原因应该就在这个地方——内存接收数据必须全字段,不能指定若干字段。

在这里插入图片描述

回归原始方法

最后结论还是用原始的办法,从AUFM表中获取数据+存表
效果立竿见影
基本上10秒之内出结果

在这里插入图片描述
ZTFICO_PRDORDER表为历史数据表,作为本期计算的期初数据。
SELECT DISTINCT
ZTFICO_PRDORDER~PROJN,
ZTFICO_PRDORDER~GJAHR,
ZTFICO_PRDORDER~PERIO,
ZTFICO_PRDORDER~PSMNG,
ZTFICO_PRDORDER~ZXXX1,
ZTFICO_PRDORDER~LJRKSJ,
ZTFICO_PRDORDER~ZXXX2,
ZTFICO_PRDORDER~DQRKSJ,
ZTFICO_PRDORDER~ZXXX3,
ZTFICO_PRDORDER~MEINS,
ZTFICO_PRDORDER~RWAER,
ZTFICO_PRDORDER~ZZT,
ZTFICO_PRDORDER~ZCPJSFS,
ZTFICO_PRDORDER~PRCTR
FROM ZTFICO_PRDORDER INNER JOIN @GT_ALV AS A1 ON A1~PROJN = ZTFICO_PRDORDER~PROJN
WHERE ZTFICO_PRDORDER~GJAHR <= @LV_LASTDAY+0(4)
AND ZTFICO_PRDORDER~PERIO <= @LV_LASTDAY+4(2)
INTO CORRESPONDING FIELDS OF TABLE @LT_ZTFICO_PRDORDER.

SORT LT_ZTFICO_PRDORDER BY PROJN GJAHR PERIO DESCENDING.
DELETE ADJACENT DUPLICATES FROM LT_ZTFICO_PRDORDER COMPARING PROJN.

LOOP AT GT_ALV INTO GS_ALV.
READ TABLE LT_ZTFICO_PRDORDER INTO LS_ZTFICO_PRDORDER WITH KEY PROJN = GS_ALV-PROJN.
IF SY-SUBRC = 0.
GS_ALV-ZXXX1 = GS_ALV-ZXXX1 + LS_ZTFICO_PRDORDER-ZXXX1.
GS_ALV-LJRKSJ = GS_ALV-LJRKSJ + LS_ZTFICO_PRDORDER-LJRKSJ.
GS_ALV-ZXXX2 = GS_ALV-ZXXX2 + LS_ZTFICO_PRDORDER-ZXXX2.
ENDIF.
MODIFY GT_ALV FROM GS_ALV.
CLEAR:LS_ZTFICO_PRDORDER.
ENDLOOP.

小结

闲人在上几篇文章有提到过关于项目财务报表设计的一些技巧,其实这些技巧并不新鲜,恰恰很多项目遇到的问题老方法,有点成熟有效,缺点需要花费额外的精力写逻辑和设计历史数据表。

这期文章主要想表达,作为一个顾问,对于开发功能的验证,必须建立在实际业务数据的考验,集成测试明显是不够的,特别是财务报表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值