Working with Sorted and Hashed Tables

Objective

After completing this lesson, you will be able to Work with sorted and hashed tables.

Try It Out: Code Example Preparation

  1. Choose Ctrl + Shift + N to create a new ABAP Repository object.
  2. Type the word database into the filter field, mark the search result Database Table, and choose Continue.
  3. Assign the new object to the package that you are working with and enter the name ZS4D401_FLIGHTS. Enter a description for the table and choose Next.
  4. Assign the object to a transport request and choose Finish .
  5. Enter the following code between the curly braces:
    Code Snippet
    Copy code
    Switch to dark mode
    1234567891011
    key client : abap.clnt not null; key carrier_id : /dmo/carrier_id not null; key connection_id : /dmo/connection_id not null; key flight_date : /dmo/flight_date not null; @Semantics.amount.currencyCode : 'zs4d401_flights.currency_code' price : /dmo/flight_price; currency_code : /dmo/currency_code; plane_type_id : /dmo/plane_type_id; seats_max : /dmo/plane_seats_max; seats_occupied : /dmo/plane_seats_occupied;
  6. Select Ctrl + F3 to activate the table.
  7. Create a new ABAP class called ZCL_FILL_ZS4D401_FLIGHTS.
  8. Enter the following code in the implementation of the main method:
    Code Snippet
    Copy code
    Switch to dark mode
    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
    DATA flights TYPE TABLE OF /dmo/flight. DATA insert_tab TYPE TABLE OF /dmo/flight. DELETE FROM ZS4D401_flights. SELECT FROM /dmo/flight FIELDS * ORDER BY carrier_Id, connection_id INTO TABLE @flights . LOOP AT flights INTO DATA(first_date). * Original table flights has 2 flights per connection. Only process the first IF sy-tabix MOD 2 = 0. CONTINUE. ENDIF. *Extend flight dates by 2000 days DO 2000 TIMES. APPEND first_date TO insert_tab. first_date-flight_date += 1. ENDDO. * ENDIF. ENDLOOP. * Read highest connection number for each flight SELECT FROM /dmo/flight AS main FIELDS carrier_Id, connection_id, flight_date, price, currency_code, plane_type_id WHERE connection_id = ( SELECT MAX( connection_id ) FROM /dmo/flight WHERE carrier_id = main~carrier_id ) AND flight_Date = ( SELECT MIN( flight_date ) FROM /dmo/flight WHERE carrier_id = main~carrier_id AND connection_id = main~connection_id ) GROUP BY carrier_id, connection_Id, flight_date, price, currency_code, plane_type_id ORDER BY carrier_id, connection_id INTO TABLE @DATA(max). *Add 50 new connection numbers and 2000 days of flights for each LOOP AT max INTO DATA(line). DO 50 TIMES. line-connection_id += 1. line-plane_type_id = SWITCH #( CONV i( line-connection_id ) MOD 2 WHEN 0 THEN 'A330' WHEN 1 THEN 'A350' ). first_date = CORRESPONDING #( line ). DATA(repetitions) = COND i( WHEN line-carrier_id = 'LH' AND line-connection_id = '0405' THEN 4000 ELSE 2000 ). DO repetitions TIMES. first_date-seats_max = 220. APPEND first_date TO insert_tab. first_date-flight_date += 1. ENDDO. ENDDO. ENDLOOP. SORT insert_tab BY carrier_Id connection_id flight_date. DELETE ADJACENT DUPLICATES FROM insert_tab COMPARING carrier_id connection_id flight_date. INSERT ZS4D401_flights FROM TABLE @insert_tab. out->write( |Generated { sy-dbcnt } rows in table ZS4D401_flights| ).
  9. Select Ctrl + F3 to activate the class.
  10. Select F9 to run the class. The main method fills an extra database table that is required for the code snippets in the next two sections.

Sorted and Hashed Tables

Up until now, we have worked with standard internal tables. The data in a standard table is not held in a particular sort order. Consequently, when you read data from the table, the system must search the table sequentially until it finds the row or rows that you need. Depending on the size of the table, this can take some time.

You can optimize the performance of read accesses to internal tables using sorted or hashed tables.

In a sorted table, the contents of the table are always sorted according to the key fields in ascending order. When you insert a new record into the table, the system ensures that it is placed at the correct position. Since the data is always sorted, the system can retrieve records more efficiently than from a standard table (as long as you follow particular rules).

Hashed tables are managed using a special hash algorithm. This ensures that the system can retrieve records very quickly even if the table is extremely large. However, this performance gain only works in very particular cases.

Access to a Sorted Table

In this video, you will see how to access a sorted table.

When you declare a hashed table, you must define it with a unique key – duplicates are never allowed.

Watch the video to know how to access a hashed table.

When to use Standard, Sorted, and Hashed Tables

If you fill an internal table and subsequently implement a loop over the entire table, you can use a standard table. The performance optimization of sorted and hashed tables is irrelevant, since there is no filter in the loop.

This example shows when you should use sorted and hashed tables. It contains a loop over the table connections using the first key field in the where clause. This is a case for using a sorted table, as the system can use the binary search technique even though the key is not fully specified.

Inside the loop, the program looks up entries in the table airlines. There are therefore repeated accesses to the table using the full key. This is an ideal case for using a hashed table.

Comparative Runtimes of Standard, Sorted, and Hashed Tables

This figure compares the runtimes of standard, sorted, and hashed tables.

Filling Sorted and Hashed Tables

When you use a standard table, you can use the APPEND statement to add the contents of a work area to the end of the table. This is not possible with hashed tables, and leads to a syntax error.

Technically, you can use the APPEND statement to fill a sorted table. However, you risk causing a runtime error if the line that you try to append does not belong at the end of the table according to the sort area. This would happen in our example.

The way to fill a hashed table and to fill a sorted table safely is to use the INSERT statement. INSERT ensures that the new row is inserted at the correct position in the table.

Try It Out: Sorted And Hashed Tables

  1. Create a new class that implements the interface IF_OO_ADT_CLASSRUN.
  2. Copy the following code snippet to the implementation part of method if_oo_adt_classrun~main( ):
    Code Snippet
    Copy code
    Switch to dark mode
    1234567891011
    * Run this class using the ABAP Profiler to measure relative access times for standard, sorted, and hashed tables data(flights) = new lcl_flights( ). flights->access_standard( ). flights->access_sorted( ). flights->access_hashed( ). out->write( |Done| ).
  3. Switch to the Local Types tab and copy the following code snippet into the editor:
    Code Snippet
    Copy code
    Switch to dark mode
    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
    CLASS lcl_flights DEFINITION. PUBLIC SECTION. METHODS constructor. METHODS access_standard. METHODS access_sorted. METHODS access_hashed. PRIVATE SECTION. DATA standard_table TYPE STANDARD TABLE OF zs4d401_flights WITH NON-UNIQUE KEY carrier_id connection_id flight_date. DATA sorted_table TYPE SORTED TABLE OF zs4d401_flights WITH NON-UNIQUE KEY carrier_id connection_id flight_date. DATA hashed_table TYPE HASHED TABLE OF zs4d401_flights WITH UNIQUE KEY carrier_id connection_id flight_date. DATA key_carrier_id TYPE /dmo/carrier_id. DATA key_connection_id TYPE /dmo/connection_id. DATA key_date TYPE /dmo/flight_date. METHODS set_line_to_read. ENDCLASS. CLASS lcl_flights IMPLEMENTATION. METHOD access_hashed. DATA(result) = hashed_table[ carrier_Id = me->key_carrier_id connection_Id = me->key_connection_id flight_date = me->key_date ]. ENDMETHOD. METHOD access_sorted. DATA(result) = sorted_table[ carrier_Id = me->key_carrier_id connection_Id = me->key_connection_id flight_date = me->key_date ]. ENDMETHOD. METHOD constructor. SELECT FROM zs4d401_flights FIELDS * INTO TABLE @standard_table. SELECT FROM zs4d401_flights FIELDS * INTO TABLE @sorted_table. SELECT FROM zs4d401_flights FIELDS * INTO TABLE @hashed_table. set_line_to_read( ). ENDMETHOD. METHOD access_standard. DATA(result) = standard_table[ carrier_Id = me->key_carrier_id connection_Id = me->key_connection_id flight_date = me->key_date ]. ENDMETHOD. METHOD set_line_to_read. DATA(line) = standard_table[ CONV i( lines( standard_table ) * '0.65' ) ]. me->key_carrier_id = line-carrier_Id. me->key_connection_Id = line-connection_id. me->key_date = line-flight_date. ENDMETHOD. ENDCLASS.
  4. Select Ctrl + F3 to activate the class.
  5. Right-click in the Editor and choose Profile As ...ABAP Application (Console).
  6. In the Details, uncheck the checkbox SQL database access and choose Finish.
  7. Switch to the ABAP Profiler perspective and double-click on the trace item (you may need to refresh the display first) .
  8. Choose Hit List.
  9. Compare the runtimes of the methods access_standard( ), access_sorted( ), and access_hashed( ).

Work with Sorted and Hashed Tables

You realize that your code contains large internal tables of table kind Standard Table. You analyze the way these tables are accessed in the code and find that they are only accessed by key. To improve the performance, you change the definition of the internal tables to either Sorted Table or Hashed Table, depending on the way they are accessed.

Template:

  • /LRN/CL_S4D401_ITS_FSYM (global Class)

Solution:

  • /LRN/CL_S4D401_ITS_TABLE_KIND (global Class)

Task 1: Copy Template (Optional)

Copy the template class. If you finished the previous exercise, you can skip this task and continue editing your class ZCL_##_SOLUTION.

Steps

  1. Copy class /LRN/CL_S4D401_ITS_FSYM to a class in your own package (suggested name: ZCL_##_SOLUTION, where ## stands for your group number).

    1. In the Project Explorer view, right-click class /LRN/CL_S4D401_ITS_FSYM to open the context menu.

    2. From the context menu, choose Duplicate ....

    3. Enter the name of your package in the Package field. In the Name field, enter the name ZCL_##_SOLUTION, where ## stands for your group number.

    4. Adjust the description and choose Next.

    5. Confirm the transport request and choose Finish.

  2. Activate the copy.

    1. Press Ctrl + F3 to activate the class.

Task 2: Adjust CONNECTIONS_BUFFER

Use the Where-used list for static attribute connections_buffer of local class LCL_PASSENGER_FLIGHT. Change the definition of connections_buffer so that it best suites the way it is accessed.

Steps

  1. Navigate to the definition of static attribute connections_buffer in local class LCL_PASSENGER_FLIGHT.

    1. For example, expand the LCL_PASSENGER_FLIGHT node in the Outline view and choose CONNECTIONS_BUFFER.

  2. Create the Where-used list for the connections_buffer attribute.

    1. In the CLASS-DATA statement, right-click on connections_buffer and choose Get Where-Used List. Alternatively, you can place the cursor on connections_buffer and press Ctrl + Shift + G.

    2. Analyze the list in the Search view below the editor view. Place the cursor over a finding to display the complete statement.

  3. Adjust the definition of the connections_buffer attribute. Choose the table kind and key definition that best fits the read access.

    1. Change the table kind to HASHED TABLE.

    2. Change the key definition to a unique key with carrier_id and connection_id as the key fields.

    3. Adjust the code as follows:

      Code Snippet
      Copy code
      Switch to dark mode
      12
      * CLASS-DATA connections_buffer TYPE TABLE OF st_connections_buffer.

Task 3: Adjust FLIGHTS_BUFFER

Use the Where-used list for static attribute flights_buffer of local class LCL_PASSENGER_FLIGHT. Change the definition of flights_buffer so that it best suites the way the attribute is accessed.

Steps

  1. Navigate to the definition of static attribute flights_buffer in local class LCL_PASSENGER_FLIGHT.

    1. For example, expand node LCL_PASSENGER_FLIGHT in the Outline view and choose FLIGHTS_BUFFER,

  2. Create the Where-used list for the flights_buffer attribute.

    1. In the CLASS-DATA statement, right-click on flights_buffer and choose Get Where-Used List. Alternatively, you can place the cursor on flights_buffer and press Ctrl + Shift + G.

    2. Analyze the list in the Search view below the editor view. Place the cursor over a finding to display the complete statement.

  3. Adjust the definition of attribute flights_buffer. Choose the table kind and key definition that best fits the read accesses.

    1. Change the table kind to SORTED TABLE.

    2. Change the key definition to a non-unique key with carrier_id, connection_id, and flight_date as the key fields.

    3. Adjust the code as follows:

      Code Snippet
      Copy code
      Switch to dark mode
      12
      * CLASS-DATA: flights_buffer TYPE TABLE OF st_flights_buffer.
  4. Analyze the syntax errors on the Problems view.

    1. Analyze the Problems view below the Editor view.

  5. Remove or comment the redundant SORT statement.

    1. Adjust the code as follows:

      Code Snippet
      Copy code
      Switch to dark mode
      123
      * SORT flights_buffer BY carrier_id connection_id flight_date.
  6. Activate and test your global class as console app.

    1. Press Ctrl + F3.

    2. Press F9.

Task 4: Quantify the Improvement

Using ABAP Profiling, quantify the performance improvement of the sorted table and hashed table.

Steps

  1. Locate the template class /LRN/CL_S4D401_ITS_FSYM in the Project Explorer view.

  2. Profile the template class /LRN/CL_S4D401_ITS_FSYM as an ABAP console app.

    1. Locate the template class /LRN/CL_S4D401_ITS_FSYM in the Project Explorer view.

    2. Right-click the name of the template class and choose Profile As2 ABAP Application (Console).

    3. Wait until the Console view appears or is refreshed.

  3. Return to your own class (ZCL_##_SOLUTION, where ## is your group number) and profile it in the same way.

    1. Locate your own class in the Project Explorer view.

    2. Right-click the name of your class and choose Profile As2 ABAP Application (Console).

    3. Wait until the Console view appears or is refreshed.

  4. Switch to the ABAP Profiling perspective and compare the two ABAP traces.

    1. For example, choose WindowPerspectiveOpen PerspectiveOther.... from the Eclipse menu, then choose ABAP Profiling and Open.

    2. Alternatively, choose the ABAP Profiling shortcut in the upper right corner of the Eclipse toolbar.

    3. In the ABAP Traces view at the bottom, expand the node that corresponds to your ABAP cloud project.

    4. Press F5 to refresh the list of trace results. The first two trace results should be named like your own ABAP class and the template class.

    5. Compare the values in column Runtime (s).

  5. After the analysis, return to the ABAP perspective.

    1. Switch the perspective as you have done before.

Log in to track your progress & complete quizzes