[ABAP] Schleifenperformance durch Feldsymbole und binäre Suche verbessern

Variante 1 (langsam: keine Optimierung)

* Verkaufsbeleg: Kopfdaten
SELECT * FROM vbak INTO TABLE @DATA(it_vbak).
* Verkaufsbeleg: Positionsdaten
SELECT * FROM vbap INTO TABLE @DATA(it_vbap).

DATA(o_timer) = cl_abap_runtime=>create_hr_timer( ).
DATA(usec_start) = o_timer->get_runtime( ).

LOOP AT it_vbak ASSIGNING FIELD-SYMBOL(<k>).
  LOOP AT it_vbap ASSIGNING FIELD-SYMBOL(<p>) WHERE vbeln EQ <k>-vbeln.
    WRITE: / <p>-vbeln, <p>-matnr.
  ENDLOOP.
ENDLOOP.

DATA(usec_end) = o_timer->get_runtime( ).
DATA(usec) = CONV decfloat16( usec_end - usec_start ).
DATA(sec) = usec / 1000000.

WRITE: / 'Laufzeit:', sec, 's'.

Variante 2 (schnell: FIELD-SYMBOL, BINARY SEARCH)

* Verkaufsbeleg: Kopfdaten
SELECT * FROM vbak INTO TABLE @DATA(it_vbak).
* Verkaufsbeleg: Positionsdaten
SELECT * FROM vbap INTO TABLE @DATA(it_vbap).

* Tabelle muss aufsteigend sortiert sein, sonst stimmt der Rückgabeindex bei der binären Suche nicht
SORT: it_vbak BY vbeln.
SORT: it_vbap BY vbeln.

DATA(o_timer) = cl_abap_runtime=>create_hr_timer( ).
DATA(usec_start) = o_timer->get_runtime( ).

LOOP AT it_vbak ASSIGNING FIELD-SYMBOL(<k>).
* binäre Suche mit READ TABLE
* -> sollen stattdessen Table-Expressions verwendet werden, muss ein Sorted Key benutzt werden
  READ TABLE it_vbap TRANSPORTING NO FIELDS WITH KEY vbeln = <k>-vbeln BINARY SEARCH.
* gefundenen Index merken
  DATA(lv_index) = sy-tabix.

  IF sy-subrc = 0.
* Suche in der sortierten Tabelle ab Index lv_index
    LOOP AT it_vbap ASSIGNING FIELD-SYMBOL(<p>) FROM lv_index WHERE vbeln = <k>-vbeln.
      WRITE: / <p>-vbeln, <p>-matnr.
    ENDLOOP.
  ELSE.
    WRITE: / 'Fehler.'.
  ENDIF.
ENDLOOP.

DATA(usec_end) = o_timer->get_runtime( ).
DATA(usec) = CONV decfloat16( usec_end - usec_start ).
DATA(sec) = usec / 1000000.

WRITE: / 'Laufzeit:', sec, 's'.

Variante 3 (am schnellsten: FIELD-SYMBOLS, HASHED TABLES, Secondary Keys)

DATA: it_vbak TYPE HASHED TABLE OF vbak WITH UNIQUE KEY vbeln.
DATA: it_vbap TYPE HASHED TABLE OF vbap WITH UNIQUE KEY vbeln posnr                             " Primary Key
                                        WITH NON-UNIQUE SORTED KEY vbeln_sort COMPONENTS vbeln. " Secondary Key

* Verkaufsbeleg: Kopfdaten
SELECT * FROM vbak INTO TABLE it_vbak.
* Verkaufsbeleg: Positionsdaten
SELECT * FROM vbap INTO TABLE it_vbap.

DATA(o_timer) = cl_abap_runtime=>create_hr_timer( ).
DATA(usec_start) = o_timer->get_runtime( ).

LOOP AT it_vbak ASSIGNING FIELD-SYMBOL(<k>).
* Nested Loop über Secondary Key vbeln_sort
* BINARY SEARCH wird durch die Verwendung des Secondary Keys implizit ausgeführt
  LOOP AT it_vbap ASSIGNING FIELD-SYMBOL(<p>) USING KEY vbeln_sort WHERE vbeln = <k>-vbeln.
    WRITE: / <p>-vbeln, <p>-matnr.
  ENDLOOP.
ENDLOOP.

DATA(usec_end) = o_timer->get_runtime( ).
DATA(usec) = CONV decfloat16( usec_end - usec_start ).
DATA(sec) = usec / 1000000.

WRITE: / 'Laufzeit:', sec, 's'.

Links

[ABAP] Daten von interner Tabelle lesen (Index, Key, Feldsymbol)

Typen & Daten

* Zeilentyp der internen Tabelle
TYPES : BEGIN OF ty_s_persons,
          pernr TYPE i,
          name  TYPE string,
          age   TYPE i,
        END OF ty_s_persons.

* Typ: Interne Tabelle mit Primärschlüssel pernr und Sekundärschlüssel persons
TYPES: ty_it_persons TYPE STANDARD TABLE OF ty_s_persons WITH KEY pernr
                                                         WITH NON-UNIQUE SORTED KEY persons COMPONENTS name.

* Daten
DATA(it_persons) = VALUE ty_it_persons(
                                        ( pernr = 1 name = |Udo|    age = 20 )
                                        ( pernr = 2 name = |Heinz|  age = 30 )
                                        ( pernr = 3 name = |Jochen| age = 40 )
                                        ( pernr = 4 name = |Ede|    age = 50 )
                                        ( pernr = 5 name = |Ina|    age = 60 )
                                        ( pernr = 6 name = |Erika|  age = 70 )
                                        ( pernr = 7 name = |Erna|   age = 80 )
                                      ).

Datensatz mit Index 1 auslesen

* table expressions
IF line_exists( it_persons[ 1 ] ).
* Datenstruktur
  DATA(lv_per1) = it_persons[ 1 ].
  WRITE: / lv_per1-pernr, lv_per1-name, lv_per1-age.

* Feldsymbol
  ASSIGN it_persons[ 1 ] TO FIELD-SYMBOL(<p1>).
  IF <p1> IS ASSIGNED.
    WRITE: / <p1>-pernr, <p1>-name, <p1>-age.
  ENDIF.
ENDIF.

* READ TABLE
* Datenstruktur
READ TABLE it_persons INDEX 1 INTO DATA(lv_per2).
IF sy-subrc = 0.
  WRITE: / lv_per2-pernr, lv_per2-name, lv_per2-age.
ENDIF.
* Feldsymbol
READ TABLE it_persons INDEX 1 ASSIGNING FIELD-SYMBOL(<p2>).
IF sy-subrc = 0 AND <p2> IS ASSIGNED.
  WRITE: / <p2>-pernr, <p2>-name, <p2>-age.
ENDIF.

Datensatz mit Primärschlüssel auslesen

* table expressions
IF line_exists( it_persons[ pernr = 2 ] ).
* Datenstruktur
  DATA(lv_per3) = it_persons[ pernr = 2 ].
  WRITE: / lv_per3-pernr, lv_per3-name, lv_per3-age.

* Feldsymbol
  ASSIGN it_persons[ pernr = 2 ] TO FIELD-SYMBOL(<p3>).
  IF <p3> IS ASSIGNED.
    WRITE: / <p3>-pernr, <p3>-name, <p3>-age.
  ENDIF.
ENDIF.

* READ TABLE
* Datenstruktur
READ TABLE it_persons WITH TABLE KEY pernr = 2 INTO DATA(lv_per4).
IF sy-subrc = 0.
  WRITE: / lv_per4-pernr, lv_per4-name, lv_per4-age.
ENDIF.
* Feldsymbol
READ TABLE it_persons WITH TABLE KEY pernr = 2 ASSIGNING FIELD-SYMBOL(<p4>).
IF sy-subrc = 0 AND <p4> IS ASSIGNED.
  WRITE: / <p4>-pernr, <p4>-name, <p4>-age.
ENDIF.

Datensatz mit Sekundärschlüssel auslesen

* table expressions
IF line_exists( it_persons[ KEY persons COMPONENTS name = 'Ina' ] ).
* Datenstruktur
  DATA(lv_per5) = it_persons[ KEY persons COMPONENTS name = 'Ina' ].
  WRITE: / lv_per5-pernr, lv_per5-name, lv_per5-age.

* Feldsymbol
  ASSIGN it_persons[ KEY persons COMPONENTS name = 'Ina' ] TO FIELD-SYMBOL(<p5>).
  IF <p5> IS ASSIGNED.
    WRITE: / <p5>-pernr, <p5>-name, <p5>-age.
  ENDIF.
ENDIF.

* READ TABLE
* Datenstruktur
READ TABLE it_persons WITH KEY persons COMPONENTS name = 'Ina' INTO DATA(lv_per6).
IF sy-subrc = 0.
  WRITE: / lv_per6-pernr, lv_per6-name, lv_per6-age.
ENDIF.
* Feldsymbol
READ TABLE it_persons WITH KEY persons COMPONENTS name = 'Ina' ASSIGNING FIELD-SYMBOL(<p6>).
IF sy-subrc = 0 AND <p6> IS ASSIGNED.
  WRITE: / <p6>-pernr, <p6>-name, <p6>-age.
ENDIF.