Производительность при использовании подстановочного знака% в Select LIKE

У меня есть следующий, ужасно медленный и неэффективный оператор, в котором я хочу выбрать все записи в e071, где поле obj_name СОДЕРЖИТ значение поля obj_name в tadir, за которым следует подстановочный знак.

LOOP AT tadir ASSIGNING <fs_tadir>.

   CONCATENATE <fs_tadir>-obj_name '%' INTO gv_obj_name.

    SELECT * FROM e071 APPENDING TABLE gt_e071 
       WHERE obj_name LIKE gv_obj_name.

ENDLOOP.

Есть ли способ сделать это более эффективным, поскольку вы не можете использовать оператор LIKE с «Для всех записей в» или объединениями?


person baarkerlounger    schedule 01.11.2013    source источник
comment
В зависимости от того, сколько записей содержится в таблицах TADIR и E071, может быть более эффективным выбрать все записи из E071, а затем удалить те, которые вам не нужны. Также старайтесь не использовать select *, если вам действительно не нужны все поля. Вы можете использовать транзакцию SAT для измерения производительности каждой транзакции. Имейте в виду, что буферизация может повлиять на любые последующие запуски, поэтому убедитесь, что вы не всегда сначала запускаете один тест, а смешиваете их, чтобы получить лучшие результаты.   -  person Esti    schedule 01.11.2013
comment
Здесь много полей ... Разве Select * не быстрее, чем выбор полей по имени (при условии, что оперативная память не является ограничивающим фактором), поскольку вам не нужно искать, какие столбцы возвращать?   -  person baarkerlounger    schedule 01.11.2013
comment
Да, если вам нужно большинство полей, SELECT *, вероятно, быстрее и, по общему признанию, проще в обслуживании. Вы всегда балансируете между снижением нагрузки на базу данных и снижением нагрузки на сеть и сохранением поддерживаемого кода.   -  person Esti    schedule 01.11.2013
comment
Вы можете создать внутреннюю таблицу со всеми нужными вам именами объектов, перейдя против TADIR с повторяющимся выбором подстановочных знаков. Затем вы можете использовать эту таблицу для выбора FOR ALL ENTRIES для E071. Это должно быть быстрее, поскольку TADIR имеет каждый объект только один раз, в то время как E071 может иметь его много раз.   -  person Gert Beukema    schedule 01.11.2013


Ответы (2)


LIKE довольно ужасен для базы данных, и поскольку у вас это как внутри цикла, вы, вероятно, сканируете весь E071 на каждой итерации цикла. Вы должны попробовать поменять местами и выбрать все в E071, а затем проверить свою таблицу внутри SELECT ... ENDSELECT. Я знаю, что это звучит нелогично, но раньше это спасло меня от созданного нами специального индекса REGUH.

SELECT * FROM e071 APPENDING TABLE gt_e071 
   WHERE obj_name LIKE gv_obj_name.

  READ TABLE tadir WITH KEY.... ASSIGNING <fs_tadir>.

ENDSELECT.

В качестве альтернативы вместо выбора с помощью одного лайка создайте диапазон значений и отправьте их в выборку сразу. Он по-прежнему будет работать плохо, но лучше.

data lt_obj_range type range of e071-obj_name.
data ls_obj_range like line of lt_obj_range.

LOOP AT tadir ASSIGNING <fs_tadir>.
   ls_obj_range-sign = 'I'.
   ls_obj_range-option = 'CP'.
   CONCATENATE <fs_tadir>-obj_name '*' INTO ls_obj_range-low.
   append ls_obj_range to lt_obj_range.

endloop.

SELECT * FROM e071 APPENDING TABLE gt_e071 
       WHERE obj_name it lt_obj_range.

Обратите внимание, что в БД есть ограничение на размер оператора выбора, поэтому, если в вашем диапазоне слишком много элементов, вы получите короткий дамп, поэтому разбейте его на диапазоны примерно 200-300 строк.

person DW8Reaper    schedule 02.11.2013

Используйте трассировку SQL (транзакция ST05) для анализа вашего запроса. Одна из основных проблем - помимо того факта, что вы потенциально бросаете тысячи запросов в базу данных - может заключаться в том, что вы вообще не используете какой-либо индекс, даже для выполнения сканирования диапазона. Это, вероятно, заставит СУБД выполнить тысячи полных сканирований таблиц. Если вы поставите PGMID и OBJECT, это должно значительно ускорить работу.

Также может быть хорошей идеей ограничить количество просматриваемых транспортных запросов с помощью его префикса. Я только что проверил несколько наших систем - в зависимости от возраста системы половина записей в E071 вообще не принадлежит транспорту. В одной системе только 75 000 записей из более чем 4,5 миллионов записей были созданы локально, остальные представляют собой отдельные списки пакетов поддержки и т.п.

Из предыдущего вопроса я у меня есть представление о том, чего вы пытаетесь достичь. Имейте в виду, что нельзя полагаться на то, что имя основного объекта находится в самом начале имени частичного объекта. Вы можете проверить кодировку функционального модуля TR_CHECK_TYPE, чтобы получить представление о том, как частичные (LIMU) записи могут быть сопоставлены с записями целого объекта (R3TR). Однако я не знаю функционального модуля, который работал бы в противоположном направлении.

На этом этапе я бы не стал беспокоиться о выборе отдельных полей вместо SELECT *. В отличие от того, что вы могли прочитать в других ответах или комментариях, E071 - это относительно узкая таблица с очень небольшим количеством полей, и вам уже нужны самые большие поля в вашем запросе. Вероятно, мало что можно получить, выбирая только отдельные поля.

person vwegert    schedule 01.11.2013
comment
Этот цикл и оператор выбора специально предназначены только для объектов методов класса - в нашей системе, по крайней мере, этот шаблон, кажется, работает для этого сценария - ограничение префиксом звучит как хорошая идея, хотя - person baarkerlounger; 01.11.2013
comment
Вам следует беспокоиться о SELECT * при запросе TADIR, поскольку это широкая таблица. Более того, в архитектуре колоночного хранилища всегда следует об этом беспокоиться. - person hennes; 01.11.2013
comment
@hennes: Если вы внимательно прочитаете вопрос, то заметите, что он запрашивает НЕ ТАДИР, а E071. - person vwegert; 01.11.2013
comment
Я знаю, но предполагаю, что в какой-то момент он должен заполнить внутренний тадир таблицы, который он перебирает. - person hennes; 01.11.2013