Автор Тема: Оптимизация ABAP-а  (Прочитано 214657 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Uukrul

  • SAP ECC 6.0 Ehp(*)
  • Administrator
  • Epic Member
  • *****
  • Сообщений: 3 729
  • Репутация: +47/-0
  • Пол: Мужской
  • YearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYears
    • Sapforum.BIZ
Re: Оптимизация ABAP-а
« Ответ #200 : Июль 03, 2016, 01:26:47 pm »
You are not allowed to view links. Register or Login
Случай с ЕИ скорее исключение из правил. В моих отчетах, заказчик хочет видеть: наименования БЕ, заводов, групп материалов, материалов, складов, счетов, контрагентов, подразделений, и т.п. Во всех отчетах с 1000+ строк лучший результат по времени давала хэш-таблица.
Ну в этом списке к исключениям единиц измерения относятся перечисленные вами БЕ, Заводы, Группы ОЗМ, Склады, Счета и не относятся сами ОЗМ и Контрагенты, т..е. это как раз ОЗМ и контрагенты являются исключением в данном случае  8), ну а так конечно все правильно написали.

Оффлайн kernel

  • Newbie
  • *
  • Сообщений: 10
  • Репутация: +0/-0
  • YearsYearsYears
Re: Оптимизация ABAP-а
« Ответ #201 : Июль 03, 2016, 05:37:35 pm »
Нет, именно ЕИ исключение из правил. Ниже тот же пример + поле завода в главной таблице.
На 52 уникальных заводах уже хэш-таблица дает лучший результат.
   8.040.207   Perform FILL_WERKS_TEST_STANDARD
   6.081.066   Perform FILL_WERKS_TEST_SORTED
   5.513.933   Perform FILL_WERKS_TEST_HASHED

Оффлайн Uukrul

  • SAP ECC 6.0 Ehp(*)
  • Administrator
  • Epic Member
  • *****
  • Сообщений: 3 729
  • Репутация: +47/-0
  • Пол: Мужской
  • YearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYears
    • Sapforum.BIZ
Re: Оптимизация ABAP-а
« Ответ #202 : Август 16, 2016, 03:21:22 pm »
Так сказать еще немного оптимизации в тему, а именно чуток заметок по работе со строками в новых версиях системы от 7.40 и старше.

В самом начале существования языка ABAP, в системе был доступен единственный способ соединения строк, это оператор CONCATENATE. Простой процесс формирования строки в цикле, предполагал выделение достаточного места для строки приемника, и далее уже выполнялось формирование результата.

ВремВып: 810 микросек
6.5.1) Базовая операция соединения строк

Код: You are not allowed to view links. Register or Login
DATA: l_long_char(10000) TYPE c,
      l_sy_index(10) TYPE c.

l_long_char = `Create long char, line = START`.
DO 100 TIMES.
  l_sy_index = sy-index.
  CONCATENATE l_long_char 'Create long char, line =' l_sy_index '.' INTO l_long_char.
ENDDO.
CONCATENATE l_long_char `Create long char, line = FINISH` INTO l_long_char.
Возможной оптимизацией в данном случае являлся только вариант прямой записи цепочки знаков в определенное место строки, без вызова операции соединения строк.

ВремВып: 605 микросек
6.5.2) Прямая запись цепочки знаков в позицию строки

Код: You are not allowed to view links. Register or Login
DATA: l_long_char(10000) TYPE c,
      l_sy_index(10)     TYPE c,
      l_add_char(100)    TYPE c.

l_long_char = `Create long char, line = START`.
DO 100 TIMES.
  l_sy_index = sy-index.
  CONCATENATE 'Create long char, line =' l_sy_index '.' INTO l_add_char.
  DATA(l_len) = strlen( l_long_char ).
  l_long_char+l_len = l_add_char.
ENDDO.
CONCATENATE l_long_char `Create long char, line = FINISH` INTO l_long_char.

Как видим прирост производительности для варианта 6.5.2 составляет 25%. Что в принципе неплохо, особенно если у вас в программе выполняется постоянная работа со строками. Кстати, на производительность в данном случае влияет размер строк с которыми выполняются операции.

В данный момент, в системе существуют новые операции сложения строк, которые являются с одной стороны, более быстрыми, а с другой более гибкими. Это операция соединения строк использующая операнд && и операция обработки шаблонов строк | |. Если сформировать аналогичный пример обработки строк, используя примеры переменных из задач 6.5.1 и 6.5.2, то производительность получится, где-то посредине, между операцией CONCATENATE и прямой записью строки в заданную позицию. В среднем пример 6.5.3 давал результат от 660 до 690 микросек. При этом обработки шаблонов всегда была чуть медленнее, чем операция соединения &&.

ВремВып: 685 микросек
6.5.3) Обработка шаблонов строк

Код: You are not allowed to view links. Register or Login
DATA: l_long_char(10000) TYPE c,

l_long_char = `Create long char, line = START`.
DO 100 TIMES.
  l_long_char = |{ l_long_char }Create long char, line ={ sy-index }.|.
ENDDO.
l_long_char = l_long_char && 'Create long char, line = FINISH'.

ВремВып: 678 микросек
6.5.4) Соединение строк операцией &&

Код: You are not allowed to view links. Register or Login
DATA: l_long_char(10000) TYPE c,

l_long_char = `Create long char, line = START`.
DO 100 TIMES.
  l_long_char = l_long_char && 'Create long char, line =' && sy-index && '.'.
ENDDO.
l_long_char = l_long_char && 'Create long char, line = FINISH'.
Из приятного, код примеров 6.5.3 и  6.5.4, выглядит менее перегруженным, а так же отсутствуют лишние переменные, так как нет ограничений на использование только определенных типов, как для оператора CONCATENATE. Но самое приятное это появление типа STRING, с которым оператор CONCATENATE работает, по моему мнению, очень плохо, а вот новые операторы работы со строками работают просто великолепно и быстро. Для примера перепишем пример 6.5.3 и 6.5.4 используя тип STRING.

ВремВып: 57 микросек
6.5.5) Обработка шаблонов строк для типа STRING

Код: You are not allowed to view links. Register or Login
DATA: l_long_string TYPE string.

l_long_string = `Create long string, line = START`.
DO 100 TIMES.
  l_long_string = |{ l_long_string }Create long char, line ={ sy-index }.|.
ENDDO.
l_long_string = l_long_string && 'Create long char, line = FINISH'.

ВремВып: 50 микросек
6.5.6) Соединение строк операцией && для типа STRING

Код: You are not allowed to view links. Register or Login
DATA: l_long_string TYPE string.

l_long_string = `Create long string, line = START`.
DO 100 TIMES.
  l_long_string = l_long_string && 'Create long char, line =' && sy-index && '.'.
ENDDO.
l_long_string = l_long_string && 'Create long char, line = FINISH'.
Как видим, скорость обработки,  отличается практически на порядок, т.е. более чем в 10 раз. Так же большим плюсом использования новых операторов является возможность, как указания различных типов переменных, так и вызова методов классов или выполнения каких-либо вычислений в процессе выполнения соединения данных. Например, выполнение вычисления значения переменной используя внутренние функции системы. В примере 6.5.7, используется возведение числа в степень.

ВремВып: 300 микросек
6.5.7) Соединение строк операцией && с динамическим вычислением значений

Код: You are not allowed to view links. Register or Login
DATA: l_long_string TYPE string.

l_long_string = `Create long string, line = START`.
DO 100 TIMES.
  l_long_string = l_long_string && 'Create long char, line =' &&
                  CONV string( ipow( base = sy-index exp = 2 ) ) &&
                  '.'.
ENDDO.
l_long_string = l_long_string && 'Create long char, line = FINISH'.
Однако, стоит вынести вычисления из операции соединения строк, как скорость выполения резко возрастает, что видно на примере 6.5.8. При этом аналогичное правило так же работает и в случае обработки соединения строк используя шаблоны, т.е. время обработки для примера 6.5.8 меньше времени выполнения для примера 6.5.7, в пять раз.


ВремВып: 57 микросек
6.5.8) Соединение строк операцией && с вынесеним операций.

Код: You are not allowed to view links. Register or Login
DATA: l_ipow type i,
      l_long_string TYPE string.

l_long_string = `Create long string, line = START`.
DO 100 TIMES.
  l_ipow = ipow( base = sy-index exp = 2 ).
  l_long_string = l_long_string && 'Create long char, line =' && l_ipow && '.'.
ENDDO.
l_long_string = l_long_string && 'Create long char, line = FINISH'.

Выводы (скорость): Где это возможно, лучше использовать тип переменной строка (STRING). Скорость обработки операции со строками, в системе, выше, чем с скорость обработки цепочек символов. Далее, не смотря на то, что новые операции соединения строк позволяют использовать динамическое вычисление значений в ходе вызова соединения строки, использовать данную возможность следует осторожно, так как оптимизации вызова таких вычислений не спросиходит и это существенно сказывается на скорости выполнения кода, что хорошо видно в примерах 6.5.7 и 6.5.8.

Оффлайн Uukrul

  • SAP ECC 6.0 Ehp(*)
  • Administrator
  • Epic Member
  • *****
  • Сообщений: 3 729
  • Репутация: +47/-0
  • Пол: Мужской
  • YearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYears
    • Sapforum.BIZ
Re: Оптимизация ABAP-а
« Ответ #203 : Апрель 06, 2019, 01:43:55 am »
Ну что-то давно небыло ничего про оптимизацию, а как показывает практика, умелыми руками можно тормознуть все и никакая HANA DB вам не поможет  8) В общем надо было тут ускорить одну программу, функциональность FM (Бюджетирование), в одном месте был кусок кода, который к позиции заказа ММ выбирал данные контракта ММ и из заголовка и позиций дополнял данные. Так как до этого с CDS (Core Data Service) особо не имел, то пришлось поставить Eclipce (Отдельная песня, со своими припевами оказалось). Далее как-то по быстрому исходя из примеров того, что написано в системе, наваял CDS. Ну что сказать, даже мой кривой пример работает несколько быстрее чем OpenSQL. В среднем цифры выходят такие:

SQL:  2 441 083
CDS:  1 557 681

Программа, примеры запросов выкусил из оригинальной программы, после чего сделал CDS и вызвал его. Стандартно CDS видится как ракурс/view.
Код: You are not allowed to view links. Register or Login
*&---------------------------------------------------------------------*
*& Report Z_TEST_SQL
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT z_test_sql.

DATA: time2     TYPE i,
      time1     TYPE i,
      time_diff TYPE i,

      time_sql  TYPE i,
      time_cds  TYPE i.

DATA: l_swap TYPE xfeld.

DATA: lt_line TYPE STANDARD TABLE OF ifmrepgax.

SELECT ebeln AS refbn,
       ebelp AS rfpos
INTO CORRESPONDING FIELDS OF TABLE @lt_line
FROM ekpo WHERE konnr <> @space.

l_swap = abap_true.
LOOP AT lt_line INTO DATA(ls_line).
  IF l_swap = abap_false.
    l_swap = abap_true.
    GET RUN TIME FIELD time1.

    SELECT SINGLE konnr,
                  ktpnr,
                  meins
    INTO (@ls_line-zz_ebeln, @ls_line-zz_ebelp, @ls_line-zz_meins)
    FROM ekpo
    WHERE ebeln = @ls_line-refbn AND
          ebelp = @ls_line-rfpos. " Сист.номер договору

    SELECT SINGLE ihrez,
                  kdatb,
                  kdate,
                  ktwrt,
                  waers,
                  matkl
    INTO (@ls_line-zz_ihrez, @ls_line-zz_kdatb, @ls_line-zz_kdate, @ls_line-zz_ktwrt, @ls_line-zz_waers, @ls_line-zz_cn_matkl)
    FROM ekko
    INNER JOIN ekpo ON ekko~ebeln = ekpo~ebeln
    WHERE ekko~ebeln = @ls_line-refbn AND
          ebelp = @ls_line-rfpos AND
          ekko~bstyp = 'K'.

    GET RUN TIME FIELD time2.
    time_diff = time2 - time1.
    time_sql = time_sql + time_diff.
  ELSE.
    l_swap = abap_false.
    GET RUN TIME FIELD time1.

    SELECT SINGLE ord_konnr AS zz_ebeln,
            ord_ktpnr AS zz_ebelp,
            ord_matkl AS zz_matkl,
            knt_ihrez AS zz_ihrez,
            knt_kdatb AS zz_kdatb,
            knt_kdate AS zz_kdate,
            knt_ktwrt AS zz_ktwrt,
            knt_waers AS zz_waers,
            knt_matkl AS zz_cn_matkl
    INTO (@ls_line-zz_ebeln, @ls_line-zz_ebelp, @ls_line-zz_matkl, @ls_line-zz_ihrez, @ls_line-zz_kdatb, @ls_line-zz_kdate, @ls_line-zz_ktwrt, @ls_line-zz_waers, @ls_line-zz_cn_matkl)
    FROM zekko_tv WHERE ebeln = @ls_line-refbn AND
                        ebelp = @ls_line-rfpos.

    GET RUN TIME FIELD time2.
    time_diff = time2 - time1.
    time_cds = time_cds + time_diff.
  ENDIF.
ENDLOOP.

WRITE: / 'SQL:', time_sql,
       / 'CDS:', time_cds.

CDS  выглядит как-то так, но даже при этом работает быстрее, а это еще процентов 70 производительности.
Код: You are not allowed to view links. Register or Login
@AbapCatalog.sqlViewName: 'ZEKKO_TV'
@VDM.viewType: #BASIC
@EndUserText.label: 'Тестовий приклад'
define view ZUTN_EKKO_TEST as select from ekko as ek
inner join ekpo as ep on ep.ebeln = ek.ebeln
inner join ekko as kt on kt.ebeln = ep.konnr and kt.bstyp = 'K'
inner join ekpo as kp on kp.ebeln = kt.ebeln and kp.ebelp = ep.ktpnr
{
    key ek.ebeln as ebeln,
    key ep.ebelp as ebelp,
   
    ep.konnr as ord_konnr,
    ep.ktpnr as ord_ktpnr,
    ep.matkl as ord_matkl,
   
    kt.ihrez as knt_ihrez,
    kt.kdatb as knt_kdatb,
    kt.kdate as knt_kdate,
    kt.ktwrt as knt_ktwrt,
    kt.waers as knt_waers,
   
    kp.matkl as knt_matkl
}
where ek.bstyp = 'F'
group by  ek.ebeln,
          ep.ebelp,
   
          ep.konnr,
          ep.ktpnr,
          ep.matkl,
   
          kt.ihrez,
          kt.kdatb,
          kt.kdate,
          kt.ktwrt,
          kt.waers,
   
          kp.matkl