ABAP Quick - Performance chained statements
Let's take a look at the performance when creating chained statements with DATA and FIELD-SYMBOL. Which variant will be ahead in terms of performance?
Table of contents
Not long ago we were in contact with a colleague who had already worked directly on projects at SAP. There he was told never to represent data declarations in chained statements, as this would suffer performance. Let's do a little experiment and measure both shapes.
Introduction
What are sets of chains and how are they formed? There are some statements in the ABAP programming language that can be used to build sentences without repeating the actual keyword. To do this, place a colon after the statement and carry out the same action over and over again, separating the elements with a comma. Here's an example:
" Chained statement
DATA:
ld_stream TYPE xstring,
ld_comment TYPE string,
" Single use
DATA ld_stream TYPE xstring.
DATA ld_comment TYPE string.
The advantage of a chain statements is that you save on coding because you can omit the keyword. Such statements are usually automatically formatted by the Pretty Printer.
Preparation
In order to follow up the statement and create a good test, we first prepare some structures and data types that we then use for our test case.
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.
To do this, we first define some simple types and then it becomes more and more complex and deep types, since we assume that the process of creating complex types will take longer.
Test case
In our test, we want to validate the data declaration for DATA and FIELD-SYMBOL, since these are the most common options. The test cases now look like we first generate some data as a chain set and then in the next step we generate the same data on a single level. We then run these routines x times in order to make differences between them measurable. Finally, the result is written to the console:
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
In the two methods, we generate a series of simple and increasingly complex types. We assume that more complex data types take longer in time because more memory needs to be allocated:
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
With the field symbols, we deliberately rely on the same generation of the data in order to be able to ensure that they can be compared with one another.
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.
Execution
In order to be able to carry out a comparison, we start the logic several times and rely on a loop run of 100000 runs. In practice, this means the routine is called that many times. This could be compared to a central building block of a processing chain, where processing is called up so often. Here is the output in the console:
What do the numbers mean in detail? If we compare the individual statements with each other, the numbers are quite similar, sometimes the individual statements are slower, sometimes the chain statement as well. Therefore, how our data is declared made no difference to the overall runtime of a program or processing. However, if we take a look at the performance between DATA and FIELD-SYMBOL, we see a bigger difference. Field symbols are clearly made available faster.
Full example
At the end of the article, the entire example so that you can recreate the experiment on your own.
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.
Conclusion
As you can see from the measurement, the impact on performance seems to be so small that you can continue to choose your favorite. It doesn't matter whether it's a chain set or a single statement, the performance should always be right. For some steps, however, you can decide whether to use field symbols or references. These are particularly worthwhile in loops, although they are mostly used in inline declarations.