Allgemein
In den folgenden Beispielen werden drei der gängigen Datenbankzugriffe über ein SELECT nach Laufzeit sowie Vor- und Nachteilen verglichen.
Variante 1 (RANGE)
* Laufzeit: 0,086142s
* Vorteile:
* - Aufteilen und Manipulieren von verknüpften DB-Abfragen
* - Abfrage in einem Block -> gut für kleine Abfragen mit wenigen RANGE-Einträgen
* - Verwendung z.B. bei Nutzung von SELECT-OPTIONS
* Nachteile:
* - Laufzeitverhalten bei großen Abfragen
* - keine Abhängigkeiten von zwei oder mehr Feldern in einem RANGE abbildbar (Verknüpfung in der WHERE-Clause erfolgt nur einzeln über AND/OR)
* - RANGES werden beim SELECT in ein Statement mit vielen ORs umgewandelt
* -> abhängig vom DB-System kommt es früher oder später zu DUMPS, wenn der RANGE zu viele Einträge beinhaltet (Speichergröße der RANGE-Table > 64kB)
DATA: lv_maktx TYPE maktx VALUE '<empty>'.
DATA(o_timer) = cl_abap_runtime=>create_hr_timer( ).
DATA(usec_start) = o_timer->get_runtime( ).
* SELECT 1: Materialnummern
SELECT m~matnr, @lv_maktx AS maktx
INTO TABLE @DATA(it_mara)
FROM mara AS m
UP TO 1000 ROWS.
DATA: rg_matnr TYPE RANGE OF matnr.
* MATNR in RANGE kopieren, darauf achten, dass die Suchfelder UNIQUE sind
rg_matnr = VALUE #( FOR <m> IN it_mara
(
sign = 'I'
option = 'EQ'
low = <m>-matnr
high = ''
) ).
* SELECT 2: Kurztexte
SELECT t~matnr, t~maktx
INTO TABLE @DATA(it_makt)
FROM makt AS t
WHERE t~matnr IN @rg_matnr
AND t~spras = @sy-langu.
* Zuweisung MATNR, MAKTX
LOOP AT it_mara ASSIGNING FIELD-SYMBOL(<t>).
IF line_exists( it_makt[ matnr = <t>-matnr ] ).
<t>-maktx = it_makt[ matnr = <t>-matnr ]-maktx.
ENDIF.
ENDLOOP.
DATA(usec_end) = o_timer->get_runtime( ).
DATA(usec) = CONV decfloat16( usec_end - usec_start ).
DATA(sec) = usec / 1000000.
WRITE: / 'Laufzeit: ', sec, 's'.
cl_demo_output=>display( it_mara ).
Variante 2 (FOR ALL ENTRIES)
* Laufzeit: 0,073252s
* Vorteile:
* - Aufteilen und Manipulieren von verknüpften DB-Abfragen
* - mehrere FOR ALL ENTRIES können pro Statement verwendet werden
* - Verwendung z.B. bei Verarbeitung von vielen Datensätzen
* Nachteile:
* - Laufzeitverhalten bei großen Abfragen
* - wenn die FOR ALL ENTRIES Liste leer ist, wir die WHERE-Clause ignoriert, was zu unerwünschten Nebeneffekten führen kann
* - FOR ALL ENTRIES werden beim SELECT in viele einzelne Statements umgewandelt
* - man sollte darauf achten, dass die Einträge in der FOR ALL ENTRIES-Tabelle nur einmal auftreten -> Performance
* - Speicherverbrauch durch die vielen Abfragen
* Anmerkungen:
* - doppelte Einträge in der FOR ALL ENTRIES Tabelle werden entfernt (SELECT DISTINCT)
* - wichtige Parameter für die Performance von FOR ALL ENTRIES sind:
* rsdb/max_blocking_factor
* rsdb/min_blocking_factor
* rsdb/max_in_blocking_factor
* rsdb/min_in_blocking_factor
* rsdb/prefer_in_itab_opt
* rsdb/prefer_fix_blocking
DATA: lv_maktx TYPE maktx VALUE '<empty>'.
DATA(o_timer) = cl_abap_runtime=>create_hr_timer( ).
DATA(usec_start) = o_timer->get_runtime( ).
* SELECT 1: Materialnummern
* darauf achten, dass die Einträge in der FOR ALL ENTRIES Tabelle UNIQUE sind
SELECT m~matnr, @lv_maktx AS maktx
INTO TABLE @DATA(it_mara)
FROM mara AS m
UP TO 1000 ROWS.
* Prüfung auf IS INITIAL ist wichtig, da sonst die WHERE-Clause im SELECT ignoriert würde
IF NOT it_mara IS INITIAL.
* SELECT 2: Kurztexte
SELECT t~matnr, t~maktx
INTO TABLE @DATA(it_makt)
FROM makt AS t
FOR ALL ENTRIES IN @it_mara
WHERE t~matnr = @it_mara-matnr
AND t~spras = @sy-langu.
* Zuweisung MATNR, MAKTX
LOOP AT it_mara ASSIGNING FIELD-SYMBOL(<m>).
IF line_exists( it_makt[ matnr = <m>-matnr ] ).
<m>-maktx = it_makt[ matnr = <m>-matnr ]-maktx.
ENDIF.
ENDLOOP.
ENDIF.
DATA(usec_end) = o_timer->get_runtime( ).
DATA(usec) = CONV decfloat16( usec_end - usec_start ).
DATA(sec) = usec / 1000000.
WRITE: / 'Laufzeit: ', sec, 's'.
cl_demo_output=>display( it_mara ).
Variante 3 (JOIN)
* Laufzeit: 0,012196s
* Vorteile:
* - wesentlich schneller als RANGE und FOR ALL ENTRIES
* - eine komplexe DB-Anfrage (generisch)
* - Verwendung bei Verarbeitung von vielen Datensätzen verteilt über viele Tabellen
* Nachteile:
* - komplexe Statements
* - schlecht zu Debuggen
DATA(o_timer) = cl_abap_runtime=>create_hr_timer( ).
DATA(usec_start) = o_timer->get_runtime( ).
* SELECT: Materialnummern, Kurztexte
SELECT m~matnr, t~maktx
INTO TABLE @DATA(it_mara)
FROM mara AS m
RIGHT OUTER JOIN makt AS t ON ( m~matnr = t~matnr )
UP TO 1000 ROWS
WHERE t~spras = @sy-langu.
DATA(usec_end) = o_timer->get_runtime( ).
DATA(usec) = CONV decfloat16( usec_end - usec_start ).
DATA(sec) = usec / 1000000.
WRITE: / 'Laufzeit: ', sec, 's'.
cl_demo_output=>display( it_mara ).
Links