This is a test message to test the length of the message box.
Login
ABAP Tipp Performance Kettensatz
Erstellt von Software-Heroes

ABAP Tipp - Performance Kettensätze

169

Schauen wir uns hier einmal die Performance beim Bilden von Kettensätzen mit DATA und FIELD-SYMBOL an. Welche Variante wird bei der Performance vorn liegen?

Werbung


Vor nicht allzu langer Zeit waren wir mit einem Kollegen im Austausch, der bereits direkt bei SAP in Projekten gearbeitet hatte. Dort wurde ihm gesagt, er sollten Datendeklarationen nie in Kettensätzen darstellen, da dadurch die Performance leiden würde. Führen wir dazu ein kleines Experiment durch und messen beide Formen.

 

Einleitung

Was sind eigentlich Kettensätze und wie werden sie gebildet? Es gibt einige Statement in der ABAP-Programmiersprache, mit diesen kann man Sätze bauen, ohne das eigentliche Schlüsselwort zu wiederholen. Dafür setzt man hinter dem Statement einen Doppelpunkt und führt die gleiche Aktion immer wieder aus, trennt die Elemente mit einem Komma. Dazu ein Beispiel:

" Chained statement
DATA:
  ld_stream  TYPE xstring,
  ld_comment TYPE string,

" Single use  
DATA ld_stream  TYPE xstring.
DATA ld_comment TYPE string.  

 

Vorteil eines Kettensatzes ist, dass man sich Coding spart, weil man das Schlüsselwort weglassen kann. Meist werden solche Statements auch durch den Pretty Printer automatisch formatiert.

 

Vorbereitung

Um nun der Aussage nachzugehen und einen guten Test zu erzeugen, bereiten wir im ersten Schritt einige Strukturen und Datentypen vor, die wir dann für unseren Testfall verwenden.

TYPES:
  td_simple_text   TYPE c LENGTH 40,
  td_simple_number TYPE p LENGTH 15 DECIMALS 2,

  BEGIN OF ts_flat_structure,
    key    TYPE td_simple_text,
    text   TYPE string,
    number TYPE i,
  END OF ts_flat_structure,
  tt_flat_standard TYPE STANDARD TABLE OF ts_flat_structure WITH EMPTY KEY,
  tt_flat_sorted   TYPE SORTED TABLE OF ts_flat_structure WITH UNIQUE KEY key,

  BEGIN OF ts_key_value,
    key   TYPE string,
    value TYPE string,
  END OF ts_key_value,
  tt_key_standard TYPE STANDARD TABLE OF ts_key_value WITH EMPTY KEY,
  tt_key_sorted   TYPE SORTED TABLE OF ts_key_value WITH UNIQUE KEY key,

  BEGIN OF ts_deep,
    key       TYPE string,
    key_value TYPE tt_key_sorted,
    flat      TYPE tt_flat_sorted,
  END OF ts_deep,
  tt_deep_standard TYPE STANDARD TABLE OF ts_deep WITH EMPTY KEY,
  tt_deep_sorted   TYPE SORTED TABLE OF ts_deep WITH UNIQUE KEY key,

  BEGIN OF ts_too_deep,
    key        TYPE string,
    structure1 TYPE ts_deep,
    structure2 TYPE ts_deep,
    table1     TYPE tt_deep_standard,
    table2     TYPE tt_deep_sorted,
  END OF ts_too_deep,
  tt_too_deep_standard TYPE STANDARD TABLE OF ts_too_deep WITH EMPTY KEY,
  tt_too_deep_sorted   TYPE SORTED TABLE OF ts_too_deep WITH UNIQUE KEY key.

 

Dazu definieren wir zuerst einige einfache Typen und danach werden es immer komplexere und tiefe Typen, da wir davon ausgehen, dass der Prozess zur Erzeugung von komplexen Typen länger dauert.

 

Testfall

Bei unserem Test wollen wir einmal die Datendeklaration für DATA und FIELD-SYMBOL validieren, da dies die gängigsten Möglichkeiten sind. Die Testfälle sehen nun so aus, dass wir zuerst einmal einige Daten als Kettensatz generieren und im nächsten Schritt dann die gleichen Daten auf einzelner Ebene. Diese Routinen lassen wir dann x-Mal laufen, um Differenzen untereinander messbar zu machen. Zum Abschluss wird das Ergebnis in die Konsole geschrieben:

GET TIME STAMP FIELD ld_start.
DO c_run_count TIMES.
  data_creation_in_one_statement( ).
ENDDO.
GET TIME STAMP FIELD ld_end.
out->write( |DATA - One Statement: { ld_end - ld_start }| ).

 

DATA

Bei den beiden Methoden generieren wir eine Reihe von einfachen und immer komplexer werdenden Typen. Wir gehen davon aus, dass komplexere Datentypen in der Zeit länger dauern, da dafür mehr Speicher allokiert werden muss:

METHOD data_creation_in_one_statement.
  DATA:
    ld_text              TYPE td_simple_text,
    ld_stream            TYPE xstring,
    ld_comment           TYPE string,
    ld_value             TYPE i,
    ld_currency          TYPE td_simple_number,
    lt_flat_standard     TYPE tt_flat_standard,
    lt_flat_sorted       TYPE tt_flat_sorted,
    lt_key_standard      TYPE tt_key_standard,
    lt_key_sorted        TYPE tt_key_sorted,
    lt_deep_standard     TYPE tt_deep_standard,
    lt_deep_sorted       TYPE tt_deep_sorted,
    lt_too_deep_standard TYPE tt_too_deep_standard,
    lt_too_deep_sorted   TYPE tt_too_deep_sorted.
ENDMETHOD.


METHOD data_creation_many_statements.
  DATA ld_text              TYPE td_simple_text.
  DATA ld_stream            TYPE xstring.
  DATA ld_comment           TYPE string.
  DATA ld_value             TYPE i.
  DATA ld_currency          TYPE td_simple_number.
  DATA lt_flat_standard     TYPE tt_flat_standard.
  DATA lt_flat_sorted       TYPE tt_flat_sorted.
  DATA lt_key_standard      TYPE tt_key_standard.
  DATA lt_key_sorted        TYPE tt_key_sorted.
  DATA lt_deep_standard     TYPE tt_deep_standard.
  DATA lt_deep_sorted       TYPE tt_deep_sorted.
  DATA lt_too_deep_standard TYPE tt_too_deep_standard.
  DATA lt_too_deep_sorted   TYPE tt_too_deep_sorted.
ENDMETHOD.

 

FIELD-SYMBOL

Bei den Feldsymbolen setzen wir bewusst auf die gleiche Erzeugung der Daten, um den Vergleich untereinander gewährleisten zu können.

METHOD fld_creation_in_one_statement.
  FIELD-SYMBOLS:
    <ld_text>              TYPE td_simple_text,
    <ld_stream>            TYPE xstring,
    <ld_comment>           TYPE string,
    <ld_value>             TYPE i,
    <ld_currency>          TYPE td_simple_number,
    <lt_flat_standard>     TYPE tt_flat_standard,
    <lt_flat_sorted>       TYPE tt_flat_sorted,
    <lt_key_standard>      TYPE tt_key_standard,
    <lt_key_sorted>        TYPE tt_key_sorted,
    <lt_deep_standard>     TYPE tt_deep_standard,
    <lt_deep_sorted>       TYPE tt_deep_sorted,
    <lt_too_deep_standard> TYPE tt_too_deep_standard,
    <lt_too_deep_sorted>   TYPE tt_too_deep_sorted.
ENDMETHOD.


METHOD fld_creation_many_statements.
  FIELD-SYMBOLS <ld_text>              TYPE td_simple_text.
  FIELD-SYMBOLS <ld_stream>            TYPE xstring.
  FIELD-SYMBOLS <ld_comment>           TYPE string.
  FIELD-SYMBOLS <ld_value>             TYPE i.
  FIELD-SYMBOLS <ld_currency>          TYPE td_simple_number.
  FIELD-SYMBOLS <lt_flat_standard>     TYPE tt_flat_standard.
  FIELD-SYMBOLS <lt_flat_sorted>       TYPE tt_flat_sorted.
  FIELD-SYMBOLS <lt_key_standard>      TYPE tt_key_standard.
  FIELD-SYMBOLS <lt_key_sorted>        TYPE tt_key_sorted.
  FIELD-SYMBOLS <lt_deep_standard>     TYPE tt_deep_standard.
  FIELD-SYMBOLS <lt_deep_sorted>       TYPE tt_deep_sorted.
  FIELD-SYMBOLS <lt_too_deep_standard> TYPE tt_too_deep_standard.
  FIELD-SYMBOLS <lt_too_deep_sorted>   TYPE tt_too_deep_sorted.
ENDMETHOD.

 

Ausführung

Um nun einen Vergleich durchführen zu können, starten wir die Logik mehrere Male und setzen dabei auf einen Schleifendurchlauf von 100000 Durchläufen. In der Praxis heißt das, die Routine wird so oft aufgerufen. Dies könnte man mit einem zentralen Baustein einer Verarbeitungskette vergleichen, wo die Verarbeitung so oft aufgerufen wird. Hier einmal die Ausgabe in der Konsole:

 

Was bedeuten die Zahlen nun im Detail? Vergleichen wir die einzelnen Statements miteinander, sind die Zahlen recht ähnlich, manchmal sind die Einzelstatements langsamer, manchmal auch der Kettensatz. Von daher machte es auf die Gesamtlaufzeit eines Programms oder einer Verarbeitung keinen Unterschied, wie unsere Daten deklariert werden. Schauen wir uns allerdings einmal die Performance zwischen DATA und FIELD-SYMBOL an, sehen wir doch einen größeren Unterschied. Feldsymbole werden eindeutig schneller zur Verfügung gestellt.

 

Vollständiges Beispiel

Zum Abschluss des Artikels noch das gesamte Beispiel, damit du den Versuch auch bei dir nachstellen kannst.

CLASS zcl_bs_demo_performance_data DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

  PROTECTED SECTION.
  PRIVATE SECTION.
    TYPES:
      td_simple_text   TYPE c LENGTH 40,
      td_simple_number TYPE p LENGTH 15 DECIMALS 2,

      BEGIN OF ts_flat_structure,
        key    TYPE td_simple_text,
        text   TYPE string,
        number TYPE i,
      END OF ts_flat_structure,
      tt_flat_standard TYPE STANDARD TABLE OF ts_flat_structure WITH EMPTY KEY,
      tt_flat_sorted   TYPE SORTED TABLE OF ts_flat_structure WITH UNIQUE KEY key,

      BEGIN OF ts_key_value,
        key   TYPE string,
        value TYPE string,
      END OF ts_key_value,
      tt_key_standard TYPE STANDARD TABLE OF ts_key_value WITH EMPTY KEY,
      tt_key_sorted   TYPE SORTED TABLE OF ts_key_value WITH UNIQUE KEY key,

      BEGIN OF ts_deep,
        key       TYPE string,
        key_value TYPE tt_key_sorted,
        flat      TYPE tt_flat_sorted,
      END OF ts_deep,
      tt_deep_standard TYPE STANDARD TABLE OF ts_deep WITH EMPTY KEY,
      tt_deep_sorted   TYPE SORTED TABLE OF ts_deep WITH UNIQUE KEY key,

      BEGIN OF ts_too_deep,
        key        TYPE string,
        structure1 TYPE ts_deep,
        structure2 TYPE ts_deep,
        table1     TYPE tt_deep_standard,
        table2     TYPE tt_deep_sorted,
      END OF ts_too_deep,
      tt_too_deep_standard TYPE STANDARD TABLE OF ts_too_deep WITH EMPTY KEY,
      tt_too_deep_sorted   TYPE SORTED TABLE OF ts_too_deep WITH UNIQUE KEY key.

    CONSTANTS:
      c_run_count TYPE i VALUE 100000.

    METHODS:
      data_creation_in_one_statement,
      data_creation_many_statements,
      fld_creation_in_one_statement,
      fld_creation_many_statements.
ENDCLASS.


CLASS zcl_bs_demo_performance_data IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    DATA:
      ld_start TYPE timestampl,
      ld_end   TYPE timestampl.

    GET TIME STAMP FIELD ld_start.
    DO c_run_count TIMES.
      data_creation_in_one_statement( ).
    ENDDO.
    GET TIME STAMP FIELD ld_end.
    out->write( |DATA - One Statement: { ld_end - ld_start }| ).

    GET TIME STAMP FIELD ld_start.
    DO c_run_count TIMES.
      data_creation_many_statements( ).
    ENDDO.
    GET TIME STAMP FIELD ld_end.
    out->write( |DATA - Many Statements: { ld_end - ld_start }| ).

    GET TIME STAMP FIELD ld_start.
    DO c_run_count TIMES.
      fld_creation_in_one_statement( ).
    ENDDO.
    GET TIME STAMP FIELD ld_end.
    out->write( |FIELD-SYMBOL - One Statement: { ld_end - ld_start }| ).

    GET TIME STAMP FIELD ld_start.
    DO c_run_count TIMES.
      fld_creation_many_statements( ).
    ENDDO.
    GET TIME STAMP FIELD ld_end.
    out->write( |FIELD-SYMBOL - Many Statements: { ld_end - ld_start }| ).
  ENDMETHOD.


  METHOD data_creation_in_one_statement.
    DATA:
      ld_text              TYPE td_simple_text,
      ld_stream            TYPE xstring,
      ld_comment           TYPE string,
      ld_value             TYPE i,
      ld_currency          TYPE td_simple_number,
      lt_flat_standard     TYPE tt_flat_standard,
      lt_flat_sorted       TYPE tt_flat_sorted,
      lt_key_standard      TYPE tt_key_standard,
      lt_key_sorted        TYPE tt_key_sorted,
      lt_deep_standard     TYPE tt_deep_standard,
      lt_deep_sorted       TYPE tt_deep_sorted,
      lt_too_deep_standard TYPE tt_too_deep_standard,
      lt_too_deep_sorted   TYPE tt_too_deep_sorted.
  ENDMETHOD.


  METHOD data_creation_many_statements.
    DATA ld_text              TYPE td_simple_text.
    DATA ld_stream            TYPE xstring.
    DATA ld_comment           TYPE string.
    DATA ld_value             TYPE i.
    DATA ld_currency          TYPE td_simple_number.
    DATA lt_flat_standard     TYPE tt_flat_standard.
    DATA lt_flat_sorted       TYPE tt_flat_sorted.
    DATA lt_key_standard      TYPE tt_key_standard.
    DATA lt_key_sorted        TYPE tt_key_sorted.
    DATA lt_deep_standard     TYPE tt_deep_standard.
    DATA lt_deep_sorted       TYPE tt_deep_sorted.
    DATA lt_too_deep_standard TYPE tt_too_deep_standard.
    DATA lt_too_deep_sorted   TYPE tt_too_deep_sorted.
  ENDMETHOD.


  METHOD fld_creation_in_one_statement.
    FIELD-SYMBOLS:
      <ld_text>              TYPE td_simple_text,
      <ld_stream>            TYPE xstring,
      <ld_comment>           TYPE string,
      <ld_value>             TYPE i,
      <ld_currency>          TYPE td_simple_number,
      <lt_flat_standard>     TYPE tt_flat_standard,
      <lt_flat_sorted>       TYPE tt_flat_sorted,
      <lt_key_standard>      TYPE tt_key_standard,
      <lt_key_sorted>        TYPE tt_key_sorted,
      <lt_deep_standard>     TYPE tt_deep_standard,
      <lt_deep_sorted>       TYPE tt_deep_sorted,
      <lt_too_deep_standard> TYPE tt_too_deep_standard,
      <lt_too_deep_sorted>   TYPE tt_too_deep_sorted.
  ENDMETHOD.


  METHOD fld_creation_many_statements.
    FIELD-SYMBOLS <ld_text>              TYPE td_simple_text.
    FIELD-SYMBOLS <ld_stream>            TYPE xstring.
    FIELD-SYMBOLS <ld_comment>           TYPE string.
    FIELD-SYMBOLS <ld_value>             TYPE i.
    FIELD-SYMBOLS <ld_currency>          TYPE td_simple_number.
    FIELD-SYMBOLS <lt_flat_standard>     TYPE tt_flat_standard.
    FIELD-SYMBOLS <lt_flat_sorted>       TYPE tt_flat_sorted.
    FIELD-SYMBOLS <lt_key_standard>      TYPE tt_key_standard.
    FIELD-SYMBOLS <lt_key_sorted>        TYPE tt_key_sorted.
    FIELD-SYMBOLS <lt_deep_standard>     TYPE tt_deep_standard.
    FIELD-SYMBOLS <lt_deep_sorted>       TYPE tt_deep_sorted.
    FIELD-SYMBOLS <lt_too_deep_standard> TYPE tt_too_deep_standard.
    FIELD-SYMBOLS <lt_too_deep_sorted>   TYPE tt_too_deep_sorted.
  ENDMETHOD.
ENDCLASS.

 

Fazit

Wie du an der Messung siehst, scheint der Einfluss auf die Performance so gering zu sein, dass du weiterhin deinen Favoriten wählen kannst. Egal ob Kettensatz oder Einzelstatement, die Performance sollte immer stimmen. Bei manchen Schritten kannst du dir aber überlegen, ob du auf Feldsymbole oder Referenzen setzt. Diese lohnen sich vor allem in Schleifen, wobei hier auch meist in Inline-Deklaration zum Einsatz kommt.

 

Quelle:
SAP Dokumentation - Kettensatz


Enthaltene Themen:
TippKettensätzeDATAFIELD-SYMBOL
Kommentare (0)



Und weiter ...

Bist du zufrieden mit dem Inhalt des Artikels? Wir posten jeden Freitag neuen Content im Bereich ABAP und unregelmäßig in allen anderen Bereichen. Schaue bei unseren Tools und Apps vorbei, diese stellen wir kostenlos zur Verfügung.


ABAP in der Praxis - Modern ABAP

Kategorie - ABAP

In dieser kleinen Aufgabe schauen wir uns bestehenden klassischen ABAP Quellcode an und versuchen diesen nach Modern ABAP zu optimieren.

27.08.2024

ABAP Tipp - Performance Datenfilterung

Kategorie - ABAP

Welche Anweisung verwendest du in ABAP zur Filterung von internen Tabellen und ist diese performant? In diesem Artikel mehr dazu.

13.08.2024

ABAP in der Praxis - Typkonvertierung

Kategorie - ABAP

Wie würdest du diese Typkonvertierung in ABAP durchführen? Ein Beispiel aus der Praxis und ein Lösungsvorschlag.

16.07.2024

ABAP Tipp - RFC Fehlerbehandlung

Kategorie - ABAP

Wie behandelt man eigentlich Fehler, wenn man über eine Destination im Funktionsbaustein kommuniziert? Mehr dazu in unserem Tipp.

05.03.2024

ABAP Tipp - CLEAR right

Kategorie - ABAP

Richtig löschen? In diesem Artikel wollen wir uns einmal anschauen, wann es Sinn macht zu löschen und wie du effektiv vorgehen kannst.

12.05.2023