Продуктивність
Три рівні, де зазвичай втрачається продуктивність ABAP-програми: доступ до бази, обробка внутрішніх таблиць, і інше (строки, цикли, конверсії). Правило номер один — не читай з БД більше ніж треба, і не читай двічі. Далі — вибрати правильний table category й уникати непотрібних копіювань.
Ця сторінка — практичні ідіоми, які дають найбільший ефект. Вимірювати реальний перфоманс — через SAT (transaction) або cl_abap_runtime.
Доступ до бази даних
Section titled “Доступ до бази даних”Звужуй result set
Section titled “Звужуй result set”Завжди фільтруй на стороні БД через WHERE, а не після вибірки в ABAP:
" Добре — БД повертає тільки потрібні рядкиSELECT key_field, char1, char2, num1, num2 FROM zdemo_abap_tab1 WHERE key_field < 500 INTO TABLE @DATA(it1).
" Погано — всі рядки летять через мережу, потім чистимо в памʼятіSELECT key_field, char1, char2, num1, num2 FROM zdemo_abap_tab1 INTO TABLE @DATA(it2).
LOOP AT it2 REFERENCE INTO DATA(dref). IF dref->key_field < 500. DELETE it2 INDEX sy-tabix. ENDIF.ENDLOOP.Також:
SELECT SINGLE— коли треба один рядок.UP TO n ROWS— коли достатньо перших n.DISTINCT— якщо дублі не потрібні.
Звужуй колонки
Section titled “Звужуй колонки”Не SELECT *, а конкретні поля. Колонковий SAP HANA тим більше любить вузькі селекти:
" ДобреSELECT carrid, connid, cityfrom, countryfr, cityto, countryto FROM zdemo_abap_flsch INTO TABLE @DATA(it7).
" Погано — тягнемо всі стовпці, включно з рідко потрібнимиSELECT * FROM zdemo_abap_flsch INTO TABLE @DATA(it8).Для UPDATE — те саме: SET col = ..., не UPDATE FROM @wa з усіма полями.
Менше звернень до БД
Section titled “Менше звернень до БД”Замість двох запитів — join:
SELECT fl~carrid, carr~carrname, fl~connid, fl~cityfrom, fl~cityto FROM zdemo_abap_flsch AS fl LEFT OUTER JOIN zdemo_abap_carr AS carr ON fl~carrid = carr~carrid INTO TABLE @DATA(it).Замість двох запитів — subquery або join з internal table:
" Підтягуємо тільки ті, чий ключ є у key_tabSELECT key_field, char1, char2, num1, num2 FROM zdemo_abap_tab1 INNER JOIN @key_tab AS tab ON zdemo_abap_tab1~key_field = tab~table_line INTO CORRESPONDING FIELDS OF TABLE @itab1.
" Альтернатива з EXISTSSELECT key_field, char1, char2, num1, num2 FROM zdemo_abap_tab1 WHERE EXISTS ( SELECT 'X' FROM @key_tab AS tab WHERE zdemo_abap_tab1~key_field = tab~table_line ) INTO CORRESPONDING FIELDS OF TABLE @itab1.Масові операції
Section titled “Масові операції”Один INSERT/UPDATE/DELETE з внутрішньої таблиці — завжди швидше за цикл з одиничними операціями:
" Одна команда — один database round-tripINSERT zdemo_tab FROM TABLE @itab.
" Погано — N round-tripsLOOP AT itab INTO DATA(wa). INSERT zdemo_tab FROM wa.ENDLOOP.Внутрішні таблиці
Section titled “Внутрішні таблиці”Вибір table category
Section titled “Вибір table category”| Операція | STANDARD | SORTED | HASHED |
|---|---|---|---|
| доступ за index | O(1) | O(1) | — |
| пошук за повним key | O(n) | O(log n) | O(1) |
| пошук за префіксом key | O(n) | O(log n) | — |
| вставка в кінець | O(1) | — | — |
| вставка за key | — | O(log n) | O(1) |
Правило: часто шукаєш за ключем на великій таблиці — HASHED або SORTED. Часто додаєш у кінець і читаєш послідовно — STANDARD. Великий обʼєм + рідкі модифікації + багато читань — SORTED/HASHED з secondary key.
Одиничний доступ
Section titled “Одиничний доступ”" O(1) — хеш-таблицяREAD TABLE hashed_tab TRANSPORTING NO FIELDS WITH TABLE KEY comp1 = sy-index.
" O(log n) — сортованаREAD TABLE sorted_tab TRANSPORTING NO FIELDS WITH TABLE KEY comp1 = sy-index.
" O(n) — STANDARD без secondary key, лінійний пошукREAD TABLE standard_tab TRANSPORTING NO FIELDS WITH TABLE KEY comp1 = sy-index.TRANSPORTING NO FIELDS — коли треба лише дізнатись наявність (перевірка sy-subrc), не копіювати весь рядок у work area.
LOOP з WHERE
Section titled “LOOP з WHERE”WHERE у LOOP AT використовує ключ, якщо поля входять у ключ таблиці:
" Повільно — STANDARD таблиця, лінійний прохідLOOP AT standard_tab REFERENCE INTO DATA(dref) WHERE comp1 = 800 AND comp2 = '800' AND comp3 = '800'. ...ENDLOOP.
" Швидше — SORTED з ключем на (comp1, comp2, comp3)LOOP AT sorted_tab_mult_key_comp REFERENCE INTO DATA(dref) WHERE comp1 = 800 AND comp2 = '800' AND comp3 = '800'. ...ENDLOOP.TRANSPORTING у MODIFY
Section titled “TRANSPORTING у MODIFY”Великі (deep) структури — передавай лише ті поля, що справді міняєш:
" Добре — копіюємо тільки comp6LOOP AT deep_standard_tab INTO DATA(wa) WHERE comp1 < 400. wa-comp6 += 1. MODIFY deep_standard_tab FROM wa TRANSPORTING comp6.ENDLOOP.
" Погано — вся структура переписуєтьсяLOOP AT deep_standard_tab INTO DATA(wa) WHERE comp1 < 400. wa-comp6 += 1. MODIFY deep_standard_tab FROM wa.ENDLOOP.Ще швидше — ASSIGNING FIELD-SYMBOL(<fs>) і писати <fs>-comp6 += 1 напряму, без MODIFY взагалі.
Block-wise обробка
Section titled “Block-wise обробка”" Один переніс всіх рядківAPPEND LINES OF str_tab_a TO str_tab_b.
" Цикл з порядковим копіюванням — повільніше, бо APPEND + копія кожного рядкаLOOP AT str_tab_a INTO DATA(wa). APPEND wa TO str_tab_b.ENDLOOP.Secondary table keys
Section titled “Secondary table keys”Великі STANDARD/SORTED таблиці, що часто читаються за різними ключами, — додай secondary key замість повторних сортувань:
DATA standard_tab_w_sec_key TYPE STANDARD TABLE OF ty_line WITH DEFAULT KEY WITH NON-UNIQUE SORTED KEY sec_key COMPONENTS comp1.
READ TABLE standard_tab_w_sec_key TRANSPORTING NO FIELDS WITH TABLE KEY sec_key COMPONENTS comp1 = sy-index.Коштує додаткової пам’яті і часу на оновлення секондарі при зміні таблиці — окупається тільки при багатьох читаннях.
SORT: явний ключ
Section titled “SORT: явний ключ”" Добре — явно вказано полеSORT standard_tab_w_default_key BY comp1 ASCENDING.
" Погано — сортує за default key, який невідомо з чого складаєтьсяSORT standard_tab_w_default_key.CLEAR vs FREE
Section titled “CLEAR vs FREE”CLEAR itab. " скидає вміст, памʼять лишається зарезервованаFREE itab. " звільняє памʼять повністюFREE має сенс, коли таблиця була великою і більше не буде наповнюватися так само.
WHILE зазвичай трохи швидший за DO + EXIT:
" ШвидшеWHILE num <= 1000. num += 1.ENDWHILE.
" ПовільнішеDO. num += 1. IF sy-index = 1000. EXIT. ENDIF.ENDDO.Стрічки
Section titled “Стрічки”Для змінних за довжиною — string швидший за c LENGTH n, бо не потребує повної перезаписи буфера:
DATA: str_a TYPE string, str_b TYPE string VALUE '#'.str_a &&= str_b. " швидше
DATA: char_a TYPE c LENGTH 1000, char_b TYPE c LENGTH 1 VALUE '#'.char_a &&= char_b. " повільніше — повний c-буферString templates (| ... |) у багатьох випадках швидші за конкатенацію backtick-літералів.
Конверсії типів
Section titled “Конверсії типів”Неявні конверсії між різними числовими типами (напр. f + i → decfloat34) — коштують. Якщо можна — тримайся одного типу:
" Добре — один тип, без конверсіїDATA: num1 TYPE decfloat34 VALUE '1.2345', num2 TYPE decfloat34 VALUE '12345', result TYPE decfloat34.result = num1 + num2.
" Гірше — f у decfloat34, i у decfloat34DATA: num1 TYPE f VALUE '1.2345', num2 TYPE i VALUE 12345, result TYPE decfloat34.result = num1 + num2.Передача параметрів
Section titled “Передача параметрів”Для великих таблиць/структур — by reference (IMPORTING itab TYPE ...) замість value. Value робить копію на кожен виклик.
Паралельна обробка
Section titled “Паралельна обробка”Для незалежних задач — CL_ABAP_PARALLEL:
DATA ref_tab TYPE cl_abap_parallel=>t_in_inst_tab.DO 5 TIMES. DATA(inst) = NEW lcl_parallel( ). APPEND inst TO ref_tab.ENDDO.
DATA(parallel) = NEW cl_abap_parallel( ).parallel->run_inst( EXPORTING p_in_tab = ref_tab IMPORTING p_out_tab = DATA(result_info) ).Чеклист
Section titled “Чеклист”- Жодного
SELECTуLOOP. -
WHEREна БД, не у ABAP. - Конкретні колонки, не
SELECT *. -
READ TABLE/LOOP WHEREвикористовують ключ. - Table category відповідає use case.
- У циклах з модифікацією —
ASSIGNING FIELD-SYMBOL(<fs>). -
MODIFY ... TRANSPORTINGдля deep-структур. -
FREEзамістьCLEARдля великих одноразових таблиць.
Адаптовано з 32_Performance_Notes.md (Apache 2.0). Повний перелік нюансів — в оригіналі.