Ещё один потолок

Работа в отчётах с параметром SELECT-OPTIONS проста.

Сначала определяем:

select-options: s_anln1 for anla-anln1.

Потом используем:

select * from anla into table gt_report where anln1 in s_anln1.

Всё просто на первый взгляд. При таком коде внутри Open SQL происходит простая работа: OpenSQL трансформируется в NativeSQL, а там подобной конструкции нет. Поэтому фактический запрос превращается приблизительно в следующее:

select * from dbchema.anla where anln1 = ‘1’ or anln1 = ‘2’ or anln1 = ‘3’;

И если бы забьём очень много значений в поле выбора, то длина получающегося в результате SQL запроса будет расти линейно. Именно где-то тут я встретился с узким местом, в котором меня стукнули по носу динамической ошибкой DBIF_RSQL_INVALID_RSQL. Интересно, а почему не SAPSQL_STMNT_TOO_LARGE?

В моём случае это примерно 9980 значений типа ANLN1. Это эмпирическое число видимо будет разниться от системе к системе, от используемого типа данных и прочих условий. И как его гарантированно предсказать в общем случае?

Есть в недавней игре Saints Row: Gat Out of Hell одно достижение: десять раз стукнуться головой о потолок.

 

Achievement unlocked

 

Как быть?

В моём случае я решил, что пользователю не следует выдумывать себе сценарии, в которых необходимо вводить десять тысяч значений в поле выбора. Ибо нефиг. Для красоты можно разве что поставить проверку на экране выбора, чтобы в эти очень редкие моменты красиво выругаться. Динамическая ошибка – это не красиво.

Опубликовано 19.02.2015 в 10:36 · Автор ivan · Ссылка
Рубрики: ABAP

6 комментариев

Подписаться на комментарии по RSS

  1. Написал(-а) Alex
    20.04.2015 в 18:35
    Ссылка

    FOR ALL ENTRIES IN itab

    решает эту проблему.

  2. Написал(-а) ivan
    21.04.2015 в 09:08
    Ссылка

    Согласен, решает. Когда работает FOR ALL ENTRIES при необходимости запрос делится на порции.
    Вот только ITAB ещё надо будет как-то заполнить. А чтобы ITAB заполнить быстро и просто снова надо снова использовать IN S_ANLN1.
    Получается так или иначе надо обращаться за LOOP AT S_ANLN1. А если мы это делаем, уже и смысла в FOR ALL ENTRIES чуть меньше.

  3. Написал(-а) Аноним
    22.04.2015 в 13:59
    Ссылка

    Вы хотите сказать что конструкции
    LOOP AT S_ANLN1
    SELECT
    ENDLOOP.
    равнозначна
    FOR ALL ENTRIES

  4. Написал(-а) ivan
    22.04.2015 в 14:37
    Ссылка

    Ну результат будет примерно одинаковым, с некоторыми упущениями в части производительности:
    1000 запросов по 1 ключу (LOOP) должны работать в целом медленнее, чем 10 запросов по 100 ключей (FOR ALL).

    Но можно же и что-то вроде:
    loop at S_ANLN1.
    if S_ANLN1-OPTION = ‘EQ’ and S_ANLN1-SIGN = ‘I’ .
    append S_ANLN1-LOW to ITAB.
    else.
    … вот тут уже может что-то начаться сложное, так как есть в природе разное…
    endif.
    endloop.

    select * for all entries in ITAB.

  5. Написал(-а) Konstantin
    30.07.2015 в 11:54
    Ссылка

    Но не следует забывать что FOR ALL ENTRIES работает как SELECT DISTINCT, т.е. если например вы выбираете позиции к документам по номерам документов есть риск потери данных. Ну это вопрос понимания программистом чего ему нужно :) Можно использовать FOR ALL ENTRIES используя полный ключ.
    Я бы например если бы использовал RANGE в запросе, то поделил примерно по 2000 записей. Тут дело не в количестве записей в RANGE а ограничение на размер запроса. В MSSQL и ORACLE это ограничение составляет 64Kb
    А еще я бы задумался над тем какой сервер работает быстрее :) Если сервер БД то тогда однозначно использовал бы RANGE, если application сервер, то тут могут быть варианты :)

  6. Написал(-а) Konstantin
    30.07.2015 в 11:56
    Ссылка

    P.S. Ну еще в рекомендациях SAP по производительности есть совет который в некоторых местах переходит в приказ :) Старайтесь уменьшить трафик между сервером БД и сервером приложений :)

Подписаться на комментарии по RSS

Написать комментарий