大型itab的收集和修改优化

时间:2018-03-02 07:51:12

标签: sap aggregation abap opensql

我有两部分代码。他们两个都处理了150万条记录,但第一部分需要20分钟而第二部分需要13.5小时!!!!!!
这是第一部分:

  loop at it_bkpf.
    select * from bseg into corresponding fields of itab
      where bukrs = it_bkpf-bukrs and
            belnr = it_bkpf-belnr and
            gjahr = it_bkpf-gjahr and
            hkont in s_hkont.

      if sy-subrc = 0 .
        itab-budat = it_bkpf-budat.

        clear *bseg .
        select single * from *bseg
          where bukrs = itab-bukrs and
            belnr = itab-belnr and
            gjahr = itab-gjahr and
            hkont = wtax .
        if sy-subrc <> 0 .
          itab-budat = '99991231'.
        endif.
      endif.
      append itab.
    endselect.
  endloop.

第13小时的第2部分如下:

sort itab by belnr.

  loop at itab where hkont(2) = '73'.
    move-corresponding itab to itab2.
    collect itab2.
  endloop.

  loop at itab2.
    lv_5per_total = con_5per_tax * itab2-dmbtr.
    lv_5per_upper = lv_5per_total + '0.02'.
    lv_5per_lower = lv_5per_total - '0.02'.

    read table itab with key belnr = itab2-belnr
                             hkont = wtax.

    if sy-subrc = 0.
      if itab-dmbtr between lv_5per_lower and lv_5per_upper.
        itab-budat = '99991231'.
        modify itab transporting budat where belnr = itab2-belnr.
      endif.
    endif.
  endloop.

有没有人知道如何修理第二部分?
一些额外的东西:
it_bkpf有150万条记录 在第一个过程之后,ITAB拥有150万条记录 在第一个循环的第二部分中,我总结了以73开头的账户的每个belnr的金额 在第二个循环中,我将每个belnr的总和与belnr / account的数量进行比较,然后执行代码所说的内容。
感谢

其他信息:
所有初始代码中的第一个存在,我添加了新的代码。 ITAB存在,ITAB2是我的。所以表格的声明是:

DATA : BEGIN OF itab OCCURS 0,
        bukrs LIKE bseg-bukrs,
        hkont LIKE bseg-hkont,
        belnr LIKE bkpf-belnr,
        gjahr LIKE bkpf-gjahr,
        dmbtr LIKE bseg-dmbtr,
        shkzg LIKE bseg-shkzg ,
        budat LIKE bkpf-budat,
        zzcode LIKE bseg-zzcode.
DATA END OF itab.
DATA : BEGIN OF itab2 OCCURS 0 ,
        belnr LIKE bkpf-belnr,
        dmbtr LIKE bseg-dmbtr,
       END OF itab2.

在您提出建议后,我做了以下更改:

types: begin of ty_belnr_sums,
        belnr like bkpf-belnr,
        dmbtr like bseg-dmbtr,
       end of ty_belnr_sums.
data: git_belnr_sums type sorted table of ty_belnr_sums
                                    with unique key belnr.
data: gwa_belnr_sums type ty_belnr_sums.

  data: lv_5per_upper type p decimals 2,
        lv_5per_lower type p decimals 2,
        lv_5per_total type p decimals 2.

  sort itab by belnr hkont.

  loop at itab where hkont(2) = '73'.
    move-corresponding itab to gwa_belnr_sums.
    collect gwa_belnr_sums into git_belnr_sums .
  endloop.

  loop at git_belnr_sums into gwa_belnr_sums.
    lv_5per_total = con_5per_tax * gwa_belnr_sums-dmbtr.
    lv_5per_upper = lv_5per_total + '0.02'.
    lv_5per_lower = lv_5per_total - '0.02'.

    read table itab with key belnr = gwa_belnr_sums-belnr
                             hkont = wtax
                    binary search.

    if sy-subrc = 0.
      if itab-dmbtr between lv_5per_lower and lv_5per_upper.
        itab-budat = '99991231'.
        modify itab transporting budat
                        where belnr = gwa_belnr_sums-belnr.
      endif.
    endif.
  endloop.

现在我在后台运行了150万条记录,并在1小时后继续运行。

4 个答案:

答案 0 :(得分:0)

这里有几个性能问题:

第一部分:

永远不要在SELECTLOOP。我永远不会说。您应该改为SELECT ... FOR ALL ENTRIESSELECT ... JOIN(BSEG是ECC中的集群表,因此不可能有JOIN,但S4 / HANA中的透明表,因此您可以使用BKPF加入它)。据我从编码中看到,您选择G / L项目,因此您可以检查使用BSIS / BSAS是否会更好(而不是BSEG)。您还可以查看表BSET(看起来您对“税”行感兴趣)

第二部分:

如果您执行LOOP WHERE条件,如果内部表格为TYPE SORTED(使用正确的密钥),则会获得最佳效果。但是,您的WHERE条件使用偏移量,因此我不确定SORTED表是否有用,但值得一试。

但真正的问题在于:COLLECT itab2COLLECT表不支持TYPE STANDARD(这在SAPHelp中有明确说明),内部表必须是TYPE HASHED(背后有技术原因,我不会详细介绍)

之后你LOOP一个内部表(itab2)和READ TABLE另一个(itab)。为了获得单行读取的最佳性能,itab必须为TYPE HASHED(或至少TYPE SORTED使用正确的密钥。)

您不必使用带有HEADER LINES的内部表,而是LOOP ... ASSIGNING FIELD-SYMBOL(<...>),因此您不再需要MODIFY,这也会略微提高性能。

答案 1 :(得分:0)

正如JozsefSzikszai所说,最好使用BSAS / BSIS,因为它们有索引。如果你真的想使用BSEG: BSEG是一个集群表。 AFAIK,这些表最好使用关键字段来执行SELECT以获取内部表,然后在内部表上处理其他字段

 select * from bseg into corresponding fields of itab
      for all entries in it_bkpf
      where bukrs = it_bkpf-bukrs and
            belnr = it_bkpf-belnr and
            gjahr = it_bkpf-gjahr.
 delete itab where hkont not in s_hkont.

在第二部分中,您将在标准表(itab)上执行READ TABLE。 使用BINARY搜索会在你的时间内切断极大 ...标准表上的读表是全表扫描(读取行直到找到值)。通过belnr和hkont(而不仅仅是belnr)和addinf BINARY SEARCH对itab进行排序将使其成为二分法搜索。

答案 2 :(得分:0)

我猜所有人都给了你优化代码的所有提示。基本上,由于您只想优化第二部分,唯一的问题似乎是itab操作(循环,读取,修改),您可以通过在内部使用索引或哈希表来改进表itab。如果这些概念不清楚,我建议使用ABAP文档:Row-Based Administration Costs of Internal TablesInternal Tables - Performance Notes

还有两件事:

  1. 您应该使用事务SAT 来衡量代码的效果,并且您将看到花费时间的操作。
  2. 与绩效无关,但与数据模型无关:财务凭证的关键由3个字段组成,公司(BUKRS),凭证编号(BELNR)和年份(GJAHR)。因此,您不应仅按文档编号进行分组(“收集”),否则您可能会混合不同公司或多年的文档。相反,请保留3个字段。
  3. 现在,如果您接受在第1部分中调整一些小东西,在阅读每个文档的BSEG行之后,您可以简单地循环这些行,不需要索引或二进制搜索或哈希表,那已经完成了。唯一要做的就是首先将BSEG的行存储在一个临时itab_temp中,一次只包含一个文档的行,这样你只能在这些行上循环,然后将它们添加到{{ 1}}。

    如果您想稍后更新BUDAT组件,而不是第1部分,则将文档密钥+ BUDAT存储在不同的内部表(例如itab)中,并定义非唯一的辅助使用文档关键字段(例如itab_budat)在itab上建立索引,您只需要这个直接的代码:

    by_doc_key

    请注意,我建议使用(非唯一)次要索引,而不是主要索引,因为您不想更改(太多)第1部分,这样可以避免潜在问题您可能拥有主索引。

    如果您需要有关术语,语法等的更多信息,可以在ABAP文档(内联或Web)中找到它们。

答案 3 :(得分:0)

很多人提出了合理的建议,特别是来自桑德拉罗西,但我只是将我的两分钱加到你最新的1小时变种中:

  • 尽可能使用字段符号。它们确实可以影响大型数据集的性能(1.5M很大,是的!)
  • 使用Sandra提出的二级密钥。这真的很重要(参见标准程序DEMO_SECONDARY_KEYS
  • 除非需要,否则不要使用INTO CORRESPONDING FIELDS,这会慢慢减慢查询速度
  • 您的代码段中的一些双重工作,因为您在第一个循环中通过itab(BSEG)收集不必要的行,但BUDAT仅在BSEG位置总和适合较低 - 较高范围时写入。因此,一些收集的款项正在浪费时间。

总而言之,我还没有完全理解您的逻辑,因为您将BUDAT写入整个匹配的行集,而仅写入匹配的组的第一行 BELNR,没有任何意义,但仍然如此。

尽管如此,如果一个人尝试在没有任何改动的情况下重复逻辑并应用新的GROUP BY语法,那么这就是人们可能得到的。

* To omit `INTO CORRESPONDING` you should properly declare your structure
* and fetch only those fields which are needed. Also avoid obsolete `OCCURS` syntax.
TYPES: BEGIN OF ty_itab,
        bukrs TYPE bseg-bukrs,
        belnr TYPE bkpf-belnr,
        gjahr TYPE bkpf-gjahr,
        hkont TYPE bseg-hkont,
        dmbtr TYPE bseg-dmbtr,
        shkzg TYPE bseg-shkzg ,
        budat TYPE bkpf-budat,
      END OF ty_itab.

TYPES: begin of ty_belnr_sums,
        belnr type bkpf-belnr,
        dmbtr type bseg-dmbtr,
       end of ty_belnr_sums.
DATA: itab TYPE TABLE OF ty_itab INITIAL SIZE 0,
      con_5per_tax type p decimals 2 value '0.03'.

SELECT g~bukrs g~belnr g~gjahr g~hkont g~dmbtr g~shkzg f~budat UP TO 1500000 rows
INTO table itab
FROM bseg AS g
JOIN bkpf AS f
 ON g~bukrs = f~bukrs
AND g~belnr = f~belnr
AND g~gjahr = f~gjahr.

DATA members LIKE itab.
LOOP AT itab ASSIGNING FIELD-SYMBOL(<fs_itab>)
                       GROUP BY ( belnr = <fs_itab>-belnr )
                                  hkont = <fs_itab>-hkont )
                       ASCENDING
                       ASSIGNING FIELD-SYMBOL(<group>).
  CLEAR members.
  CHECK <group>-hkont(2) = '73'.

  LOOP AT GROUP <group> ASSIGNING FIELD-SYMBOL(<group_line>).
    members = VALUE #( BASE members ( <group_line> ) ).
  ENDLOOP.

  DATA(sum) = REDUCE dmbtr( INIT val TYPE dmbtr
                            FOR wa IN members
                            NEXT val = val + wa-dmbtr ).

  IF members[1]-dmbtr BETWEEN con_5per_tax * sum - '0.02' AND con_5per_tax * sum + '0.02'.
    <first_line>-budat = '99991231'.
  ENDIF.
ENDLOOP.

在我对1.5M数据集的测试期间,我使用GET RUN TIME FIELD测量了运行时间并获得了以下结果。

旧片段:

enter image description here

我的片段:

enter image description here