ABAP Virtual Sorting: Tabellen verarbeiten ohne physische Sortierung

Kategorie
ABAP
Veröffentlicht
Autor
Johannes

Virtual Sorting ermöglicht die sortierte Verarbeitung interner Tabellen, ohne die physische Reihenfolge der Zeilen zu ändern. Mit der SORT ... BY-Syntax in Tabellenausdrücken und Iterationen kannst du Daten in einer bestimmten Reihenfolge durchlaufen, während die Originaltabelle unverändert bleibt.

Was ist Virtual Sorting?

Virtual Sorting ist ein Konzept, bei dem die Sortierreihenfolge temporär für eine Operation definiert wird, ohne die Tabelle selbst zu modifizieren. Das ist besonders nützlich, wenn:

  • Mehrere Sortierreihenfolgen parallel benötigt werden
  • Die Originaltabelle nicht verändert werden soll
  • Performance bei großen Tabellen kritisch ist
AspektPhysisches SORTVirtual Sorting
OriginaltabelleWird verändertBleibt unverändert
ReihenfolgeDauerhaftTemporär für Operation
Mehrere SortierungenNacheinanderParallel möglich
SpeicherIn-PlaceZusätzlicher Index

Verfügbarkeit

Virtual Sorting mit FOR ... IN ... USING KEY und dynamischen Keys ist seit ABAP 7.40 verfügbar. Die erweiterten Möglichkeiten mit sekundären Keys sind vollständig ABAP Cloud-kompatibel.

Praxisbeispiel: Verkaufsdaten analysieren

Ein typisches Szenario ist die Analyse von Verkaufsdaten, die in verschiedenen Sortierungen ausgewertet werden sollen:

CLASS zcl_virtual_sorting DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
TYPES: BEGIN OF ty_s_sale,
sale_id TYPE i,
product TYPE string,
region TYPE string,
amount TYPE p DECIMALS 2,
sale_date TYPE d,
END OF ty_s_sale.
" Tabelle mit sekundären Keys für virtuelle Sortierung
TYPES ty_t_sales TYPE SORTED TABLE OF ty_s_sale
WITH UNIQUE KEY sale_id
WITH NON-UNIQUE SORTED KEY by_amount COMPONENTS amount DESCENDING
WITH NON-UNIQUE SORTED KEY by_region COMPONENTS region
WITH NON-UNIQUE SORTED KEY by_date COMPONENTS sale_date DESCENDING.
ENDCLASS.
CLASS zcl_virtual_sorting IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(lt_sales) = VALUE ty_t_sales(
( sale_id = 1 product = 'Laptop' region = 'Nord' amount = '1200.00' sale_date = '20260110' )
( sale_id = 2 product = 'Monitor' region = 'Süd' amount = '450.00' sale_date = '20260115' )
( sale_id = 3 product = 'Tastatur' region = 'Nord' amount = '89.00' sale_date = '20260112' )
( sale_id = 4 product = 'Server' region = 'West' amount = '5500.00' sale_date = '20260108' )
( sale_id = 5 product = 'Mouse' region = 'Süd' amount = '35.00' sale_date = '20260120' )
).
out->write( '=== Originale Reihenfolge (nach sale_id) ===' ).
LOOP AT lt_sales INTO DATA(ls_sale).
out->write( |{ ls_sale-sale_id }: { ls_sale-product } - { ls_sale-amount }| ).
ENDLOOP.
out->write( '' ).
out->write( '=== Nach Umsatz (höchster zuerst) ===' ).
LOOP AT lt_sales INTO ls_sale USING KEY by_amount.
out->write( |{ ls_sale-product }: { ls_sale-amount } EUR| ).
ENDLOOP.
out->write( '' ).
out->write( '=== Nach Region ===' ).
LOOP AT lt_sales INTO ls_sale USING KEY by_region.
out->write( |{ ls_sale-region }: { ls_sale-product }| ).
ENDLOOP.
out->write( '' ).
out->write( '=== Nach Datum (neueste zuerst) ===' ).
LOOP AT lt_sales INTO ls_sale USING KEY by_date.
out->write( |{ ls_sale-sale_date DATE = USER }: { ls_sale-product }| ).
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Sekundäre Keys für Virtual Sorting

Der Schlüssel zu Virtual Sorting sind sekundäre Tabellenkeys. Sie definieren alternative Sortierreihenfolgen, die der ABAP-Kernel automatisch verwaltet.

Key-Typen

" Primärer Key (Identifikation)
WITH UNIQUE KEY sale_id
" Sekundärer SORTED Key (automatisch sortiert gehalten)
WITH NON-UNIQUE SORTED KEY by_amount COMPONENTS amount DESCENDING
" Sekundärer HASHED Key (für schnelle Lookups)
WITH UNIQUE HASHED KEY by_product COMPONENTS product

Vergleich: Physisch vs. Virtuell

CLASS zcl_sort_comparison DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
TYPES: BEGIN OF ty_s_item,
item_id TYPE i,
name TYPE string,
value TYPE p DECIMALS 2,
END OF ty_s_item.
TYPES ty_t_items TYPE SORTED TABLE OF ty_s_item
WITH UNIQUE KEY item_id
WITH NON-UNIQUE SORTED KEY by_value COMPONENTS value DESCENDING.
ENDCLASS.
CLASS zcl_sort_comparison IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(lt_items) = VALUE ty_t_items(
( item_id = 1 name = 'A' value = '100.00' )
( item_id = 2 name = 'B' value = '300.00' )
( item_id = 3 name = 'C' value = '200.00' )
).
" PHYSISCHE Sortierung - verändert die Tabelle
DATA(lt_sorted_copy) = lt_items.
SORT lt_sorted_copy BY value DESCENDING.
out->write( '=== Physisch sortierte Kopie ===' ).
LOOP AT lt_sorted_copy INTO DATA(ls_sorted).
out->write( |{ ls_sorted-name }: { ls_sorted-value }| ).
ENDLOOP.
" VIRTUELLE Sortierung - Original bleibt unverändert
out->write( '' ).
out->write( '=== Virtuell sortiert (USING KEY) ===' ).
LOOP AT lt_items INTO DATA(ls_virtual) USING KEY by_value.
out->write( |{ ls_virtual-name }: { ls_virtual-value }| ).
ENDLOOP.
" Original ist unverändert
out->write( '' ).
out->write( '=== Original (unverändert) ===' ).
LOOP AT lt_items INTO DATA(ls_original).
out->write( |{ ls_original-name }: { ls_original-value }| ).
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Virtual Sorting mit FOR-Ausdrücken

Virtual Sorting funktioniert auch in funktionalen Konstrukten wie FOR-Schleifen und REDUCE:

CLASS zcl_virtual_sort_for DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
TYPES: BEGIN OF ty_s_order,
order_id TYPE i,
customer TYPE string,
amount TYPE p DECIMALS 2,
priority TYPE i,
END OF ty_s_order.
TYPES ty_t_orders TYPE SORTED TABLE OF ty_s_order
WITH UNIQUE KEY order_id
WITH NON-UNIQUE SORTED KEY by_priority COMPONENTS priority
WITH NON-UNIQUE SORTED KEY by_amount COMPONENTS amount DESCENDING.
TYPES: BEGIN OF ty_s_output,
rank TYPE i,
info TYPE string,
END OF ty_s_output.
TYPES ty_t_output TYPE STANDARD TABLE OF ty_s_output WITH EMPTY KEY.
ENDCLASS.
CLASS zcl_virtual_sort_for IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(lt_orders) = VALUE ty_t_orders(
( order_id = 101 customer = 'Müller' amount = '500.00' priority = 2 )
( order_id = 102 customer = 'Schmidt' amount = '1500.00' priority = 1 )
( order_id = 103 customer = 'Weber' amount = '300.00' priority = 3 )
( order_id = 104 customer = 'Fischer' amount = '2000.00' priority = 1 )
).
" FOR mit USING KEY - Reihenfolge für Konstruktor bestimmen
DATA(lt_by_priority) = VALUE ty_t_output(
FOR ls_order IN lt_orders USING KEY by_priority
INDEX INTO lv_idx
( rank = lv_idx
info = |{ ls_order-customer } (Prio { ls_order-priority }): { ls_order-amount } EUR| )
).
out->write( '=== Nach Priorität sortiert (VALUE FOR) ===' ).
LOOP AT lt_by_priority INTO DATA(ls_output).
out->write( |{ ls_output-rank }. { ls_output-info }| ).
ENDLOOP.
" Top 2 nach Betrag mit REDUCE
DATA(lv_top2_total) = REDUCE p DECIMALS 2(
INIT sum = CONV p DECIMALS 2( 0 )
count = 0
FOR ls_ord IN lt_orders USING KEY by_amount
WHILE count < 2
NEXT sum = sum + ls_ord-amount
count = count + 1
).
out->write( '' ).
out->write( |Top 2 Bestellungen Summe: { lv_top2_total } EUR| ).
" Filter kombiniert mit virtueller Sortierung
DATA(lt_high_priority) = VALUE ty_t_output(
FOR ls_o IN lt_orders USING KEY by_amount
WHERE ( priority <= 2 )
INDEX INTO lv_i
( rank = lv_i
info = |{ ls_o-customer }: { ls_o-amount }| )
).
out->write( '' ).
out->write( '=== Hohe Priorität, nach Betrag ===' ).
LOOP AT lt_high_priority INTO DATA(ls_hp).
out->write( |{ ls_hp-rank }. { ls_hp-info }| ).
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Performance-Betrachtung

Virtual Sorting mit sekundären Keys bietet Performance-Vorteile, hat aber auch Kosten:

Wann sekundäre Keys verwenden

SituationEmpfehlung
Häufig gleiche Sortierung✅ Sekundärer Key lohnt sich
Einmalige Sortierung❌ Physisches SORT effizienter
Mehrere parallele Sortierungen✅ Ideal für sekundäre Keys
Sehr große Tabellen (>100.000)⚠️ Speicherkosten abwägen
Häufige INSERT/DELETE⚠️ Key-Pflege kostet Performance

Performance-Messung

CLASS zcl_virtual_sort_perf DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
TYPES: BEGIN OF ty_s_data,
id TYPE i,
value TYPE p DECIMALS 2,
END OF ty_s_data.
" Mit sekundärem Key
TYPES ty_t_with_key TYPE SORTED TABLE OF ty_s_data
WITH UNIQUE KEY id
WITH NON-UNIQUE SORTED KEY by_value COMPONENTS value.
" Ohne sekundären Key
TYPES ty_t_no_key TYPE SORTED TABLE OF ty_s_data
WITH UNIQUE KEY id.
ENDCLASS.
CLASS zcl_virtual_sort_perf IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
" Testdaten generieren
DATA lt_with_key TYPE ty_t_with_key.
DATA lt_no_key TYPE ty_t_no_key.
DO 10000 TIMES.
DATA(lv_value) = CONV p DECIMALS 2( sy-index MOD 1000 ).
INSERT VALUE #( id = sy-index value = lv_value ) INTO TABLE lt_with_key.
INSERT VALUE #( id = sy-index value = lv_value ) INTO TABLE lt_no_key.
ENDDO.
" Variante 1: Virtual Sorting mit Key
DATA(lv_start1) = cl_abap_context_info=>get_system_time( ).
DATA(lv_sum1) = REDUCE p DECIMALS 2(
INIT sum = CONV p DECIMALS 2( 0 )
FOR ls_data IN lt_with_key USING KEY by_value
NEXT sum = sum + ls_data-value
).
DATA(lv_end1) = cl_abap_context_info=>get_system_time( ).
" Variante 2: Physisches SORT + Iteration
DATA(lt_copy) = CORRESPONDING ty_t_no_key( lt_no_key ).
DATA(lv_start2) = cl_abap_context_info=>get_system_time( ).
SORT lt_copy BY value.
DATA(lv_sum2) = REDUCE p DECIMALS 2(
INIT sum = CONV p DECIMALS 2( 0 )
FOR ls_data IN lt_copy
NEXT sum = sum + ls_data-value
).
DATA(lv_end2) = cl_abap_context_info=>get_system_time( ).
out->write( |Virtual Sorting: { lv_end1 - lv_start1 } ms| ).
out->write( |Physisches SORT: { lv_end2 - lv_start2 } ms| ).
out->write( |Summe identisch: { COND #( WHEN lv_sum1 = lv_sum2 THEN 'Ja' ELSE 'Nein' ) }| ).
ENDMETHOD.
ENDCLASS.

Best Practices

DO: Sekundäre Keys sinnvoll nutzen

" GUT: Key für häufig genutzte Sortierung
TYPES ty_t_products TYPE SORTED TABLE OF ty_s_product
WITH UNIQUE KEY product_id
WITH NON-UNIQUE SORTED KEY by_price COMPONENTS price DESCENDING.
" Iteration in gewünschter Reihenfolge
LOOP AT lt_products INTO DATA(ls_prod) USING KEY by_price.
" Verarbeitung nach Preis absteigend
ENDLOOP.

DON’T: Übermäßig viele Keys definieren

" SCHLECHT: Zu viele sekundäre Keys
" Jeder Key belegt Speicher und kostet bei INSERT/DELETE
TYPES ty_t_overkill TYPE SORTED TABLE OF ty_s_data
WITH UNIQUE KEY id
WITH NON-UNIQUE SORTED KEY k1 COMPONENTS field1
WITH NON-UNIQUE SORTED KEY k2 COMPONENTS field2
WITH NON-UNIQUE SORTED KEY k3 COMPONENTS field3
WITH NON-UNIQUE SORTED KEY k4 COMPONENTS field4
WITH NON-UNIQUE SORTED KEY k5 COMPONENTS field5. " Zu viel!
" BESSER: Nur die wirklich benötigten Keys
TYPES ty_t_balanced TYPE SORTED TABLE OF ty_s_data
WITH UNIQUE KEY id
WITH NON-UNIQUE SORTED KEY by_priority COMPONENTS priority.

ABAP Cloud Kompatibilität

AspektStatus
BTP ABAP Environment✅ Vollständig unterstützt
S/4HANA Cloud✅ Vollständig unterstützt
S/4HANA On-Premise✅ Ab 7.40
Released API Status✅ Kernsprachfeature

Virtual Sorting mit sekundären Keys ist ein Kernsprachfeature von ABAP und kann in allen ABAP Cloud-Umgebungen ohne Einschränkungen verwendet werden.

Zusammenfassung

Virtual Sorting ermöglicht elegante Lösungen für Mehrfach-Sortierungen:

  • Sekundäre Keys definieren alternative Sortierreihenfolgen
  • USING KEY aktiviert die virtuelle Sortierung in LOOP und FOR
  • Original bleibt unverändert - keine Seiteneffekte
  • Performance-Vorteil bei wiederholten Sortierungen
  • Speicherkosten für sekundäre Keys beachten
  • Kombinierbar mit REDUCE, VALUE, und anderen funktionalen Konstrukten

Besonders bei Reporting-Szenarien, wo Daten in verschiedenen Ansichten dargestellt werden müssen, ist Virtual Sorting eine elegante und performante Lösung.

Weiterführende Artikel