ECC 的福音用自定义表提高 BSEG 取数性能

作者:ABAP老白 约 6 分钟阅读 更新日期:2025-03-02 1 年前更新 标签:Basis, 系统管理
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图

在S4和HANA版本的ECC Ehp8之前,BSEG出于安全原因被设计为簇表, 无法创建索引,不能使用JOIN语句,

这导致BSEG性能很差,取数相当的痛苦,相信每一个老ABAPer都受到过这个问题的折磨。多年前我曾经用自定义表的方式解决了这个问题,并且取得了非常好的效果。

解决的办法其实很简单,总体思路是以空间换时间。既然问题的根本原因是簇表,那么另外建一个透明表ZBSEG,数据和BSEG相同,能建索引,能JOIN,取数的时候在这个表取不就简单高效多了?而且因为标准事务码还是用的BSEG的数据,安全性也没有被破坏。甚至表内还可以加入BKPF的常用字段,

取数的时候不需要再JOIN BKPF,进一步提升性能。 这个方案基本可以一劳永逸的解决BSEG取数性能差的问题。

此方案的关键点在于ZBSEG数据的写入,必须实时和BSEG保持一致,所以需要使用增强的方法在生成凭证或者修改凭证的时候实时更新到ZBSEG,然后需要取BSEG的自开发程序都可以改为取ZBSEG。

首先建自定义表ZBSEG( 注 意 创建合适 的索引 )

ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图

BKPF的常用字段:

ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图

更新ZBSEG的代码, 函数 ZBTE_ZBSEG_SAVE:

ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
FUNCTION zbte_zbseg_save.*"----------------------------------------------------------------------*"*"更新函数模块:*"*"*"局部接口:*" IMPORTING*" VALUE(UPDKZ) TYPE UPDKZ_D OPTIONAL*" VALUE(I_XBKPF) TYPE BKPF OPTIONAL*" VALUE(I_YBKPF) TYPE BKPF OPTIONAL*" TABLES*" T_BKPF STRUCTURE BKPF OPTIONAL*" T_BSEG STRUCTURE BSEG OPTIONAL*" XBSEG STRUCTURE FBSEG OPTIONAL*"---------------------------------------------------------------------- DATA: lt_bseg TYPE TABLE OF bseg WITH HEADER LINE. DATA: lt_save TYPE TABLE OF zbseg WITH HEADER LINE. IF updkz = 'I'. LOOP AT t_bseg. READ TABLE t_bkpf WITH KEY bukrs = t_bseg-bukrs belnr = t_bseg-belnr gjahr = t_bseg-gjahr. MOVE-CORRESPONDING t_bseg TO lt_save. MOVE-CORRESPONDING t_bkpf TO lt_save. APPEND lt_save.CLEAR lt_save. ENDLOOP. ELSEIF updkz = 'U'. IF i_xbkpf-bktxt <> i_ybkpf-bktxt OR i_xbkpf-xblnr <> i_ybkpf-xblnr OR i_xbkpf-xref1_hd <> i_ybkpf-xref1_hd OR i_xbkpf-xref2_hd <> i_ybkpf-xref2_hd OR xbseg[] IS INITIAL. SELECT * INTO CORRESPONDING FIELDS OF TABLE lt_bseg FROM bseg WHERE bukrs = i_xbkpf-bukrs AND belnr = i_xbkpf-belnr AND gjahr = i_xbkpf-gjahr. CHECK sy-subrc = 0. LOOP AT lt_bseg. READ TABLE xbseg WITH KEY buzei = lt_bseg-buzei. IF sy-subrc = 0. MOVE-CORRESPONDING xbseg TO lt_bseg. ENDIF.

MOVE-CORRESPONDING lt_bseg TO lt_save. MOVE-CORRESPONDING i_xbkpf TO lt_save. APPEND lt_save.CLEAR lt_save. ENDLOOP. ELSE. LOOP AT xbseg. MOVE-CORRESPONDING xbseg TO lt_save. MOVE-CORRESPONDING i_xbkpf TO lt_save. APPEND lt_save.CLEAR lt_save. ENDLOOP. ENDIF. ENDIF.

MODIFY zbseg FROM TABLE lt_save. LOOP AT t_bkpf WHERE stblg IS NOT INITIAL. "凭证冲销 UPDATE zbseg SET stblg = t_bkpf-belnr stjah = t_bkpf-gjahr WHERE bukrs = t_bkpf-bukrs AND belnr = t_bkpf-stblg AND gjahr = t_bkpf-stjah. ENDLOOP.ENDFUNCTION.

然后参照 : [ 实时发送SAP会计凭证到外部系统

](http://mp.weixin.qq.com/s?__biz=MzA5NjUwMjQ1Mw==&mid=2649907569&idx=1&sn=0ea65ab84b7f46ce38e3d364cdd24b48&chksm=88a9d6abbfde5fbd3ff5d19340a627f62de0d64ea834358f3b443ebbfc6bad355e75441831a5&scene=21#wechat_redirect)

,在3个BTE函数调用此函数。

ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图
ECC 的福音用自定义表提高 BSEG 取数性能 - 封面图

到这儿,实时更新ZBSEG表的功能就做完了。但是因为有历史数据,所以需要初始化ZBSEG表的初始化程序,以及日常中检查ZBSEG是否跟BKPF、BSEG数据是否一致的检查程序,分别是程序ZBSEG_INIT和ZBSEG_CHECK。

*&---------------------------------------------------------------------**& Report ZBSEG_INIT*& 初始化ZBSEG,使用游标的方式防止内表过大导致系统DUMP*&---------------------------------------------------------------------*REPORT zbseg_init NO STANDARD PAGE HEADING.

DATA: gt_bseg TYPE TABLE OF zbseg WITH HEADER LINE.DATA: gt_bkpf TYPE HASHED TABLE OF bkpf WITH HEADER LINE WITH UNIQUE KEY mandt bukrs belnr gjahr.DATA: gv_cursor TYPE cursor, gv_dbcntr TYPE i, gv_dbcntw TYPE i. SELECT-OPTIONS: s_bukrs FOR gt_bseg-bukrs, s_gjahr FOR gt_bseg-gjahr.PARAMETERS p_trunc AS CHECKBOX.

AT SELECTION-SCREEN OUTPUT. %_s_bukrs_%_app_%-text = '公司代码'. %_s_gjahr_%_app_%-text = '年度'. %_p_trunc_%_app_%-text = '初始化前先清空表ZBSEG(所有数据)'.

START-OF-SELECTION. IF p_trunc = 'X'. EXEC SQL. truncate table zbseg ENDEXEC. MESSAGE s000(oo) WITH 'TRUNCATE FINISH'. ENDIF.

OPEN CURSOR WITH HOLD gv_cursor FOR SELECT * FROM bseg WHERE bukrs IN s_bukrs AND gjahr IN s_gjahr. DO. FETCH NEXT CURSOR gv_cursor INTO CORRESPONDING FIELDS OF TABLE gt_bseg PACKAGE SIZE 5000. IF sy-subrc NE 0. EXIT. ENDIF. gv_dbcntr = sy-dbcnt.

CLEAR gt_bkpf[]. SELECT * INTO TABLE gt_bkpf FROM bkpf FOR ALL ENTRIES IN gt_bseg WHERE bukrs = gt_bseg-bukrs AND belnr = gt_bseg-belnr AND gjahr = gt_bseg-gjahr. LOOP AT gt_bseg. READ TABLE gt_bkpf WITH TABLE KEY mandt = sy-mandt bukrs = gt_bseg-bukrs belnr = gt_bseg-belnr gjahr = gt_bseg-gjahr. IF sy-subrc NE 0. MESSAGE s000(oo) WITH gt_bseg-bukrs gt_bseg-belnr gt_bseg-gjahr '在BKPF不存在'. DELETE gt_bseg. CONTINUE. ENDIF.

MOVE-CORRESPONDING gt_bkpf TO gt_bseg. MODIFY gt_bseg. ENDLOOP. INSERT zbseg FROM TABLE gt_bseg ACCEPTING DUPLICATE KEYS. gv_dbcntw = gv_dbcntw + sy-dbcnt. MESSAGE s000(oo) WITH '累计读出条数:' gv_dbcntr ' 累计写入条数:' gv_dbcntw. CALL FUNCTION 'DB_COMMIT'. ENDDO. CLOSE CURSOR gv_cursor. CALL FUNCTION 'DB_COMMIT'.

*&---------------------------------------------------------------------**& Report ZBSEG_CHECK*& 检查ZBSEG的正确性*&---------------------------------------------------------------------*REPORT zbseg_check NO STANDARD PAGE HEADING.

DATA: gt_bseg1 TYPE TABLE OF zbseg WITH HEADER LINE, gt_zbseg TYPE HASHED TABLE OF zbseg WITH UNIQUE KEY bukrs belnr gjahr buzei WITH HEADER LINE.DATA: gt_bkpf TYPE HASHED TABLE OF bkpf WITH HEADER LINE WITH UNIQUE KEY mandt bukrs belnr gjahr.DATA: gv_cursor TYPE cursor, gv_dbcntr TYPE i, gv_dbcntw TYPE i, gv_errcnt TYPE i, gv_rtmsg TYPE bapi_msg.DATA: go_sdescr TYPE REF TO cl_abap_structdescr, gt_comp TYPE cl_abap_structdescr=>component_table WITH HEADER LINE.FIELD-SYMBOLS: <gv_fld1> TYPE ANY, <gv_fld2> TYPE ANY. SELECT-OPTIONS: s_bukrs FOR gt_bseg1-bukrs, s_gjahr FOR gt_bseg1-gjahr, s_belnr FOR gt_bseg1-belnr.PARAMETERS p_pasize TYPE i DEFAULT 10000.PARAMETERS p_errcnt TYPE i DEFAULT 1000.PARAMETERS p_corect AS CHECKBOX.PARAMETERS p_insert AS CHECKBOX.PARAMETERS p_usejob AS CHECKBOX DEFAULT 'X'.

AT SELECTION-SCREEN OUTPUT. %_s_bukrs_%_app_%-text = '公司代码'. %_s_gjahr_%_app_%-text = '年度'. %_s_belnr_%_app_%-text = '凭证号'. %_p_pasize_%_app_%-text = '每次处理BSEG条数'. %_p_errcnt_%_app_%-text = '最大错误数'. %_p_corect_%_app_%-text = '修改字段值错误数据'. %_p_insert_%_app_%-text = '插入缺少数据'. %_p_usejob_%_app_%-text = 'JOB执行'.

START-OF-SELECTION. IF p_usejob = 'X' AND sy-batch = ''. PERFORM submi

...

ABAP老白

关于作者:ABAP老白

企业信息化与 SAP 技术顾问,长期专注 SAP ABAP、FI/CO、MM、SD 等模块的技术分享与实战经验总结。查看更多介绍

来源说明:本文内容由「ECC的福音用自定义表提高BSEG取数性能.md」整理生成,仅用于内部技术分享与学习交流。