Параллельный курсор (Parallel Cursor) в ABAP

Одна из основных задач ABAP разработчика заключается в оптимизации уже ранее написанного кода. Как правило, потенциально «опасных» конструкций не так и много, сюда можно отнести типы таблиц (стандартные, сортированные, хешированные), нюансы конструкции «select endselect» и, конечно, вложенные циклы!


Создадим программу, в которой прочитаем таблицу со списком аэропортов SAIRPORT и таблицу со списком полетов SFLIGHTS. Затем для каждого аэропорта найдем соответствующие полёты и выведем информацию о полётах на экран.

REPORT z_parallel_cursor.

DATA: lt_airports TYPE STANDARD TABLE OF s_airport,
      lt_flights  TYPE STANDARD TABLE OF sflights.

SELECT id FROM sairport INTO TABLE lt_airports.
SELECT * FROM sflights INTO TABLE lt_flights.

LOOP AT lt_airports ASSIGNING FIELD-SYMBOL(<fs_airport>).
  LOOP AT lt_flights ASSIGNING FIELD-SYMBOL(<fs_flight>) WHERE airpfrom = <fs_airport>.
    WRITE:/ <fs_flight>-airpfrom, <fs_flight>-cityfrom, <fs_flight>-cityto.
  ENDLOOP.
ENDLOOP.

В данном примере встречается потенциально не эффективная конструкция — вложенные циклы (Nested Loops). При больших количествах строк во внутренних таблицах данная конструкция может выполнятся существенное время.

Перепишем программу, использовав концепцию параллельного курсора (Parallel Cursor):

REPORT z_parallel_cursor.

DATA: lt_airports TYPE STANDARD TABLE OF s_airport,
      lt_flights  TYPE STANDARD TABLE OF sflights,
      lv_index    TYPE sy-tabix.

SELECT id FROM sairport INTO TABLE lt_airports.
SELECT * FROM sflights INTO TABLE lt_flights.

SORT lt_airports.
SORT lt_flights BY airpfrom.

LOOP AT lt_airports ASSIGNING FIELD-SYMBOL(<fs_airport>).

  READ TABLE lt_flights TRANSPORTING NO FIELDS WITH KEY airpfrom = <fs_airport> BINARY SEARCH.
  IF sy-subrc IS INITIAL.
    lv_index = sy-tabix.

    LOOP AT lt_flights ASSIGNING FIELD-SYMBOL(<fs_flight>) FROM lv_index.
      IF <fs_flight>-airpfrom NE <fs_airport> .
        EXIT.
      ENDIF.

      WRITE:/ <fs_flight>-airpfrom, <fs_flight>-cityfrom, <fs_flight>-cityto.
    ENDLOOP.

  ENDIF.
ENDLOOP.

Какие изменения мы сделали:

  • Сделали сортировку таблиц для выполнения двоичного (бинарного) поиска значения.
  • Первый цикл оставляем неизменным.
  • В самом начале цикла методом двоичного поиска ищем первый элемент с искомым ключом.
  • Если такой элемент находим, то запоминаем его положение (sy-tabix) в таблице.
  • Второй цикл мы начинаем с индекса первой найденной записи.
  • Так как таблица у нас сортирована по искомому ключу, то все элементы с данным ключом будут идти один за другим.
  • В цикле мы проверяем соответствие ключа искомому значению. Если записи с таким ключом закончились, то выходим из второго цикла.

Получается, что мы не перебираем каждый элемент внутреннего цикла на соответствие условию, а вычленяем среди всех строк только строки, которые удовлетворяют нашему поиску, отбрасывая строки, которые будут следовать после искомых.