This is a test message to test the length of the message box.
Login
ABAP Quick Performance INSERT vs VALUE
Created by Software-Heroes

ABAP Quick - Performance INSERT vs VALUE

In this article we take a look at the performance of the insert operations APPEND, INSERT and VALUE with regard to tables and evaluate the performance and stability during development.

Advertising

In addition to Append and Insert, you can now also use Value to append rows to a table or to insert them into sorted tables. We want to take a look at the performance when adding data sets and do an automated test. For comparison, we have also included the "old" append in order to perhaps determine further differences here.

 

Structure

We use a console application to carry out the test and create a method for each test case. The generation and storage of the data takes place in the method, so that after leaving the method, the garbage collector can clean up the old variables and thus free the memory. The runtime measurement takes place outside of this method in MAIN. We have provided a small and a large table for the test, each of which represents a different level of complexity.

TYPES:
  BEGIN OF ts_small,
    integer TYPE i,
    text    TYPE c LENGTH 35,
  END OF ts_small,
  tt_small        TYPE STANDARD TABLE OF ts_small WITH EMPTY KEY,
  tt_small_sorted TYPE SORTED TABLE OF ts_small WITH UNIQUE KEY integer,

  BEGIN OF ts_big,
    integer TYPE i,
    text    TYPE c LENGTH 35,
    ltext   TYPE string,
    amt     TYPE p LENGTH 15 DECIMALS 2,
    curr    TYPE waers,
    tab     TYPE string_table,
  END OF ts_big,
  tt_big        TYPE STANDARD TABLE OF ts_big WITH EMPTY KEY,
  tt_big_sorted TYPE SORTED TABLE OF ts_big WITH UNIQUE KEY integer.

 

To generate the individual filled lines (structure), we provide two auxiliary methods that provide us with different lines based on the index, so that the inserted data are not always the same. The large structure also has a deep structure because we provide a string table.

METHOD create_small_line.
  rs_result-integer = id_index.
  rs_result-text = |Text for number { id_index }|.
ENDMETHOD.


METHOD create_big_line.
  rs_result-integer = id_index.
  rs_result-text = |Text for number { id_index }|.
  rs_result-ltext = |Some longtext with the number { id_index }. Add this to your table|.
  rs_result-amt = CONV #( id_index ).
  rs_result-curr = 'EUR'.
  rs_result-tab = VALUE #( FOR ld_x = 1 THEN ld_x + 1 WHILE ld_x < 5 ( |Entry { ld_x }| ) ).
ENDMETHOD.

 

For the runtime measurement we use the class CL_ABAP_RUNTIME which gives us a start time and we can subtract this from the end time. We then output this output directly to the Eclipse console. At this point you have the option to generate a timer with high or low accuracy.

DATA(lo_timer) = cl_abap_runtime=>create_hr_timer( ).

DATA(ld_start) = lo_timer->get_runtime( ).
" Run test method
out->write( |TEST_METHOD_NAME: { lo_timer->get_runtime( ) - ld_start }| ).

 

Test

We carry out the tests three times and determine the mean value as the result for the performance measurement. In the screenshots you can see the individual values again in detail and how they behave for the corresponding table sizes.

 

The results of the performance measurement on average then look as follows. The values have been converted into seconds to make it easier to compare:

Type of test APPEND INSERT VALUE
Standard table (small) 5,06 5,06 5,87
Standard table (big) 36,3 109,5 116,9
Sortierte table (small) 6,60 6,31 7,54
Sortierte table (big) 110,4 110,3 115,7

 

In almost all cases, the Value command does a little worse and has a worse performance than the insert. There are hardly any differences between insert and append, unless we look at the time when appending complex and large structures to a standard table. Here Append can score with more than 50% gain in runtime and depends on the other two statements. When using a sorted table, there are hardly any deviations.

 

Hint: In our example we use an APPEND on a sorted table with a key. This only works because the key is appended to the table in ascending order (SY-INDEX). For our example it is sufficient, but you should never append a sorted table, otherwise an exception (key violation) will occur.

 

Example

Here again the full class to simulate the test. The number of generated data records can be regulated via the constant C_LOOP_VALUE. With around 7.5 million entries in the test table, the process ran out of memory on our system and it was aborted, so we set the value to 5 million.

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

  PROTECTED SECTION.
  PRIVATE SECTION.
    CONSTANTS:
      c_loop_value TYPE i VALUE 5000000.

    TYPES:
      BEGIN OF ts_small,
        integer TYPE i,
        text    TYPE c LENGTH 35,
      END OF ts_small,
      tt_small        TYPE STANDARD TABLE OF ts_small WITH EMPTY KEY,
      tt_small_sorted TYPE SORTED TABLE OF ts_small WITH UNIQUE KEY integer,

      BEGIN OF ts_big,
        integer TYPE i,
        text    TYPE c LENGTH 35,
        ltext   TYPE string,
        amt     TYPE p LENGTH 15 DECIMALS 2,
        curr    TYPE waers,
        tab     TYPE string_table,
      END OF ts_big,
      tt_big        TYPE STANDARD TABLE OF ts_big WITH EMPTY KEY,
      tt_big_sorted TYPE SORTED TABLE OF ts_big WITH UNIQUE KEY integer.

    METHODS:
      create_small_line
        IMPORTING
                  id_index         TYPE i
        RETURNING VALUE(rs_result) TYPE ts_small,

      create_big_line
        IMPORTING
                  id_index         TYPE i
        RETURNING VALUE(rs_result) TYPE ts_big,

      test_append_small,
      test_append_big,
      test_insert_small,
      test_insert_big,
      test_value_small,
      test_value_big,

      sort_append_small,
      sort_append_big,
      sort_insert_small,
      sort_insert_big,
      sort_value_small,
      sort_value_big.
ENDCLASS.


CLASS zcl_test_table_performance IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    DATA(lo_timer) = cl_abap_runtime=>create_hr_timer( ).

    DATA(ld_start) = lo_timer->get_runtime( ).
    test_append_small( ).
    out->write( |TEST_APPEND_SMALL: { lo_timer->get_runtime( ) - ld_start }| ).

    ld_start = lo_timer->get_runtime( ).
    test_insert_small( ).
    out->write( |TEST_INSERT_SMALL: { lo_timer->get_runtime( ) - ld_start }| ).

    ld_start = lo_timer->get_runtime( ).
    test_value_small( ).
    out->write( |TEST_VALUE_SMALL : { lo_timer->get_runtime( ) - ld_start }| ).

    ld_start = lo_timer->get_runtime( ).
    test_append_big( ).
    out->write( |TEST_APPEND_BIG  : { lo_timer->get_runtime( ) - ld_start }| ).

    ld_start = lo_timer->get_runtime( ).
    test_insert_big( ).
    out->write( |TEST_INSERT_BIG  : { lo_timer->get_runtime( ) - ld_start }| ).

    ld_start = lo_timer->get_runtime( ).
    test_value_big( ).
    out->write( |TEST_VALUE_BIG   : { lo_timer->get_runtime( ) - ld_start }| ).


    ld_start = lo_timer->get_runtime( ).
    sort_append_small( ).
    out->write( |SORT_APPEND_SMALL: { lo_timer->get_runtime( ) - ld_start }| ).

    ld_start = lo_timer->get_runtime( ).
    sort_insert_small( ).
    out->write( |SORT_INSERT_SMALL: { lo_timer->get_runtime( ) - ld_start }| ).

    ld_start = lo_timer->get_runtime( ).
    sort_value_small( ).
    out->write( |SORT_VALUE_SMALL : { lo_timer->get_runtime( ) - ld_start }| ).

    ld_start = lo_timer->get_runtime( ).
    sort_append_big( ).
    out->write( |SORT_APPEND_BIG  : { lo_timer->get_runtime( ) - ld_start }| ).

    ld_start = lo_timer->get_runtime( ).
    sort_insert_big( ).
    out->write( |SORT_INSERT_BIG  : { lo_timer->get_runtime( ) - ld_start }| ).

    ld_start = lo_timer->get_runtime( ).
    sort_value_big( ).
    out->write( |SORT_VALUE_BIG   : { lo_timer->get_runtime( ) - ld_start }| ).
  ENDMETHOD.


  METHOD create_small_line.
    rs_result-integer = id_index.
    rs_result-text = |Text for number { id_index }|.
  ENDMETHOD.


  METHOD create_big_line.
    rs_result-integer = id_index.
    rs_result-text = |Text for number { id_index }|.
    rs_result-ltext = |Some longtext with the number { id_index }. Add this to your table|.
    rs_result-amt = CONV #( id_index ).
    rs_result-curr = 'EUR'.
    rs_result-tab = VALUE #( FOR ld_x = 1 THEN ld_x + 1 WHILE ld_x < 5 ( |Entry { ld_x }| ) ).
  ENDMETHOD.


  METHOD test_append_small.
    DATA:
      lt_table TYPE tt_small.

    DO c_loop_value TIMES.
      DATA(ls_line) = create_small_line( sy-index ).
      APPEND ls_line TO lt_table.
    ENDDO.
  ENDMETHOD.


  METHOD test_append_big.
    DATA:
      lt_table TYPE tt_big.

    DO c_loop_value TIMES.
      DATA(ls_line) = create_big_line( sy-index ).
      APPEND ls_line TO lt_table.
    ENDDO.
  ENDMETHOD.


  METHOD test_insert_small.
    DATA:
      lt_table TYPE tt_small.

    DO c_loop_value TIMES.
      DATA(ls_line) = create_small_line( sy-index ).
      INSERT ls_line INTO TABLE lt_table.
    ENDDO.
  ENDMETHOD.


  METHOD test_insert_big.
    DATA:
      lt_table TYPE tt_big.

    DO c_loop_value TIMES.
      DATA(ls_line) = create_big_line( sy-index ).
      INSERT ls_line INTO TABLE lt_table.
    ENDDO.
  ENDMETHOD.


  METHOD test_value_small.
    DATA:
      lt_table TYPE tt_small.

    DO c_loop_value TIMES.
      DATA(ls_line) = create_small_line( sy-index ).
      lt_table = VALUE #( BASE lt_table ( integer = ls_line-integer text = ls_line-text ) ).
    ENDDO.
  ENDMETHOD.


  METHOD test_value_big.
    DATA:
      lt_table TYPE tt_big.

    DO c_loop_value TIMES.
      DATA(ls_line) = create_big_line( sy-index ).
      lt_table = VALUE #( BASE lt_table (
        integer = ls_line-integer
        text = ls_line-text
        ltext = ls_line-ltext
        amt = ls_line-amt
        curr = ls_line-curr
        tab = ls_line-tab
      ) ).
    ENDDO.
  ENDMETHOD.


  METHOD sort_append_small.
    DATA:
      lt_table TYPE tt_small_sorted.

    DO c_loop_value TIMES.
      DATA(ls_line) = create_small_line( sy-index ).
      APPEND ls_line TO lt_table.
    ENDDO.
  ENDMETHOD.


  METHOD sort_append_big.
    DATA:
      lt_table TYPE tt_big_sorted.

    DO c_loop_value TIMES.
      DATA(ls_line) = create_big_line( sy-index ).
      APPEND ls_line TO lt_table.
    ENDDO.
  ENDMETHOD.


  METHOD sort_insert_small.
    DATA:
      lt_table TYPE tt_small_sorted.

    DO c_loop_value TIMES.
      DATA(ls_line) = create_small_line( sy-index ).
      INSERT ls_line INTO TABLE lt_table.
    ENDDO.
  ENDMETHOD.


  METHOD sort_insert_big.
    DATA:
      lt_table TYPE tt_big_sorted.

    DO c_loop_value TIMES.
      DATA(ls_line) = create_big_line( sy-index ).
      INSERT ls_line INTO TABLE lt_table.
    ENDDO.
  ENDMETHOD.


  METHOD sort_value_small.
    DATA:
      lt_table TYPE tt_small_sorted.

    DO c_loop_value TIMES.
      DATA(ls_line) = create_small_line( sy-index ).
      lt_table = VALUE #( BASE lt_table ( integer = ls_line-integer text = ls_line-text ) ).
    ENDDO.
  ENDMETHOD.


  METHOD sort_value_big.
    DATA:
      lt_table TYPE tt_big_sorted.

    DO c_loop_value TIMES.
      DATA(ls_line) = create_big_line( sy-index ).
      lt_table = VALUE #( BASE lt_table (
        integer = ls_line-integer
        text = ls_line-text
        ltext = ls_line-ltext
        amt = ls_line-amt
        curr = ls_line-curr
        tab = ls_line-tab
      ) ).
    ENDDO.
  ENDMETHOD.
ENDCLASS.

 

Conclusion

The VALUE command is very extensive and offers many new features, but you can still confidently use INSERT when transferring the data records in order to stay on the safe and stable side and take the performance advantage with you. In the meantime, we generally advise against APPEND, as the table type can change in the course of development, thus saving subsequent changes to the source code. You can find out more about this in another article from us.


Included topics:
QuickINSERTVALUEAPPENDPerformance
Comments (0)
Advertising

ABAP Quick - Creation of test data

Category - ABAP

What challenges do you have when setting up test tables and test data and how can machine processing help you?

06/25/2021

ABAP Unit Quick Guide

Category - ABAP

Our current e-book is now available on Amazon, we would like to briefly show you what you can expect in the book and what it will bring you in the end.

05/28/2021

ABAP Quick - RFC Buffer

Category - ABAP

Here is a little tip from us about what can go wrong with the buffer when reading via RFC and what you should definitely pay attention to.

04/23/2021

ABAP Quick - Wait for task

Category - ABAP

Today a tip for asynchronous processing or if you want to put processing in a separate task in special situations. What happens afterwards?

03/05/2021

ABAP - BOPF Quick Guide (Update)

Category - ABAP

A little update to our book that we published. For all people who find the paperless office boring.

10/23/2020