SAP小技巧 字符串连接的性能优化

问题

之前写了一个接口程序: SAP中的数据获取后,根据不同的层级结构,拼接到一个TXT文件中(有点像IDOC的文件输出). 业务反馈存在性能问题. 大概需要三个小时才能完成数据的读取及文件的写入.

本文主要介绍字符串连接的性能优化方式

ST12

推荐使用事务代码ST12做程序的性能分析.这个工具会把所有的执行步骤,模块详细记录一个执行时间. 可以很快定位性能最差的模块及语句

填写要分析的程序/事务,点击 execute / start trace 按钮

c267eac783385277eac102b1a46321f8.png

执行后系统记录的分析结果

30533b4c7cc51c10514ebd2c93cb8dc3.png

选中分析结果,点击ABAP trace按钮,按net time in 排序,可以看到耗时最大的模块,快速定位存在性能的代码.

2972fbea84aee8ae2f42002d7a68d072.png

问题分析

通过ST12分析结果. 发现在嵌套循环的一个子循环耗时较长. 于是尝试改变字符串关联的方式. 从方式1 调整为方式2. 

  1. 内层循环直接拼接到最终字符串

  2. 内存循环先拼接到子串, 外层循环把子串拼接到最终字符串

01

方式1 

内层循环直接拼接到最终字符串

LOOT AT ITAB.

LOOP AT ITAB1

GV_STR = GV_STR && 'A'.

GV_STR = GV_STR && 'B'.

ENDLOOP .

ENDLOOP.

02

方式2

内存循环先拼接到子串, 外层循环把子串拼接到最终字符串

LOOP AT ITAB2.

CLEAR LV_STR.

LOOP AT ITAB1

LV_STR = LV_STR && 'A'.

LV_STR = LV_STR && 'B'.

ENDLOOP .

GV_STR = GV_STR && LV_STR.

ENDLOOP.

通过上述方式2 优化程序后,对比二者的性能差异. 发现方式2性能好于方式1

尤其是最终的字符串非常大的情况下. 上述优化方案将极大的增加性能

如下图, 性能优化提升4倍多.

1906915250156ff7c16da4f645ff4a35.png

如果文件很大, 性能差异更大

665d36ca3bb9db06b74b05dfd07a700a.png

 两种拼接命令

concatenate lv_str 'NEW STRING' INTO lv_str

lv_str = lv_str &&  'NEW STRING' 

实际测试concatenate方式性能差于操作符 && . 但concatenate 命令可以在连接的字符串中添加空格或其它字符. 操作符&&做不到这一点.

原因猜测

直接在最终字符串上拼接所有的变量,当最终字符串较大或较复杂时. 拼接命令可能会导致系统循环整个字符串到字符串的最后一个字符位置. 方式1会导致不断循环这个较大的字符串.

而使用嵌套循环中的子串先拼接,再拼接到最终的字符串中. 这样就会减少较大的字符串本身的循环.

该猜想无法验证. 仅仅是根据两种方式的巨大时间差异来猜想的. 

验证猜测

使用下面的测试代码验证. 发现二者性能差异不大. 并且依赖于外层循环与内层循环的个数.

非常奇怪这个验证结论和优化程序的结论不一致. 可能实际程序的拼接逻辑远比示例程序的拼接逻辑复杂或者有特殊字符的参与(换行符号)触发了猜想的字符串本身的循环,导致了这二者结论的差异.

*&---------------------------------------------------------------------*
*& Report ZTS_STRING_CONN
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT ZTS_STRING_CONN.


PARAMETERS: P_TIMES TYPE I DEFAULT 1000,
            P_TIME2 TYPE I DEFAULT 1000.
PARAMETERS: P_CON AS CHECKBOX.
DATA: LV_STR TYPE STRING.


START-OF-SELECTION.


  CL_DEMO_OUTPUT=>BEGIN_SECTION( '直接连接' ).
  GET RUN TIME FIELD DATA(T1).
  DO P_TIMES TIMES.
    DO P_TIME2 TIMES.
      IF P_CON = ''.
        LV_STR = LV_STR && 'JUST_TEST_STRING_JOIN' && CL_ABAP_CHAR_UTILITIES=>NEWLINE.
      ELSE.
        CONCATENATE LV_STR 'JUST_TEST_STRING_JOIN' INTO LV_STR.
      ENDIF.
    ENDDO.
  ENDDO.
  GET RUN TIME FIELD DATA(T2).
  CL_DEMO_OUTPUT=>WRITE( STRLEN( LV_STR ) ).
  CL_DEMO_OUTPUT=>WRITE( T2 - T1 ).


  CL_DEMO_OUTPUT=>BEGIN_SECTION( '借用子串连接' ).
  DATA: LV_SUBSTR TYPE STRING.
  CLEAR LV_STR.
  GET RUN TIME FIELD DATA(T3).
  DO P_TIMES TIMES.
    CLEAR LV_SUBSTR.
    DO P_TIME2 TIMES.
      IF P_CON = ''.
        LV_SUBSTR = LV_SUBSTR && 'JUST_TEST_STRING_JOIN'  && CL_ABAP_CHAR_UTILITIES=>NEWLINE..
      ELSE.
        CONCATENATE LV_SUBSTR 'JUST_TEST_STRING_JOIN' INTO LV_SUBSTR.
      ENDIF.
    ENDDO.
    LV_STR = LV_STR && LV_SUBSTR.
  ENDDO.
  GET RUN TIME FIELD DATA(T4).
  CL_DEMO_OUTPUT=>WRITE( STRLEN( LV_STR ) ).
  CL_DEMO_OUTPUT=>WRITE( T4 - T3 ).


  CL_DEMO_OUTPUT=>DISPLAY( ).

总结

但总体上讲, 如果排除了其它性能问题,并且直接拼接到最终字符串导致性能问题, 则可以尝试在嵌套循环(子循环)中先拼接子串, 在主循环中再把子串拼接到最终的字符串. 

实测这个性能差异可能是数倍到数百倍.

THE

END

约定

如果你对这篇文章感兴趣,请帮忙点赞,在看,分享.       

请微信联系管理员: 

syjf1976 

sharry_xlp  

Yannick_Duan 

申请进入公众号讨论群提问或者参与话题讨论

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值