Меню

Оптимизация SQL-запросов в программах ABAP

|

В статье рассматриваются техники оптимального кодирования SQL-запросов на языке ABAP. Материал представлен в виде «правил» и не является чем-то оригинальным. В том или ином объёме он присутствует во многих англоязычных источниках. Основная идея всех этих правил — свести к минимуму нагрузку на СУБД системы SAP за счёт оптимального кодирования SQL-запросов и переноса по возможности большей работы по обработке данных на сторону серверов приложений системы.


 

Прусов Михаил, фрилансер. С 1998 года работает консультантом SAP по базису и администрированию. Имеет сертификаты: Technology Consultant SAP NetWeaver'04 — SAP WebAS for Oracle, IBM eServer Certified Specialist: p5 and pSeries Technical Sales Support. В качестве фрилансера работает более 7 лет. Только за период 2007-2009 годов более чем у 20 заказчиков успешно осуществил инсталляцию ландшафта решений SAP, базисную поддержку проекта внедрения, внедрение функциональности SAP Solution Manager Operations и обучил специалистов Клиента. Проводит консультации по вопросам производительности, отказоустойчивости, безопасности продуктов SAP.

 

В статье рассматриваются техники оптимального кодирования SQL-запросов на языке ABAP. Материал представлен в виде «правил» и не является чем-то оригинальным. В том или ином объёме он присутствует во многих англоязычных источниках. Основная идея всех этих правил — свести к минимуму нагрузку на СУБД системы SAP за счёт оптимального кодирования SQL-запросов и переноса по возможности большей работы по обработке данных на сторону серверов приложений системы.

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

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

Прекрасным средством оценки реальной пользы от приведённых ниже советов, а также от многих других приёмов оптимизации, служит транзакция SE30 (раздел "Tips&Tricks").

 

  • Правило 1. Выбирайте только необходимые записи
  • Правило 2. Выбирайте только необходимые поля
  • Правило 3. Минимизируйте число запросов
  • Правило 4. Упрощайте фразу WHERE
  • Правило 5. Избегайте ненужной загрузки БД
  • Источники информации

 

Правило 1. Выбирайте только необходимые записи

Выбирайте из базы данных минимально необходимое число записей. Зачастую это правило сводится к тому, что SQL-запрос должен иметь должным образом построенную фразу WHERE. Это правило особенно важно для таблиц размер которых превышает 1 MB. Придерживайтесь следующих принципов при кодировании программ, выбирающих данные из БД:

 

  • Если программа содержит оператор CHECK для полей таблицы, выбираемой в цикле SELECT…ENDSELECT, замените оператор CHECK на соответствующее условие во фразе WHERE SQL-запроса.
  • Не должны использоваться SQL-операторы без фразы WHERE к постоянно растущим таблицам — например, к таблицам хранящим транзакционные данные.
  • Избегайте повторных выборок данных. В сложных отчётах с несколькими проходами обработки одних и тех же данных предварительно выберете данные во внутренние ABAP-таблицы, а затем используйте эти внутренние таблицы для многократного доступа к данным.
  • Часто фраза WHERE в SQL-запросах, определяющих факт наличия данных в БД, выглядит следующим образом:

       CLEAR found.
       SELECT * FROM dbtable WHERE cond.
          found = 'X'.
          EXIT.
       ENDSELECT.
    

    Недостаток кода, приведённого выше заключается в том, что база данных будет полагать, что необходимо найти ВСЕ записи, удовлетворяющие условию. Это может сказаться как на плане выполнения запроса, который выберет база данных, так на числе выбранных записей — интерфейс СУБД сервера приложений SAP может принять определённое число записей в свой буфер ввода-вывода прежде, чем вернёт управление программе ABAP. Более эффективным будет следующий код:

       CLEAR found.
       SELECT * FROM dbtable UP TO 1 WHERE cond.
       ENDSELECT.
       IF sy-subrc = 0.
          found = 'X'.
       ENDIF.
    

    Этот код проинформирует базу данных о том, что нужна единственная запись, удовлетворяющая условию.

 

Правило 2. Выбирайте только необходимые поля

Сведите к минимуму объем пересылаемых данных от базы данных к серверу приложения.

 

  • SQL-оператор с фразой SELECT * приводит к пересылке на сервер приложений SAP всех полей таблицы. Если данные из всех полей не нужны, лучше будет явно указать список выбираемых полей из таблицы базы данных или использовать соответствующее представление-проекцию (projection view).
  • Существует

Если хотите прочитать статью полностью и оставить свои комментарии присоединяйтесь к sapland

У вас уже есть учетная запись?

Войти

Обсуждения Количество комментариев14

Комментарий от  

Денис Мужжухин

  |  22 октября 2010, 16:00

а разве select single не эффективнее select ... up to 1 rows ... endselect? одно обращение к базе вместо двух должно быть быстрее.

Комментарий от  

Олег Точенюк

  |  22 октября 2010, 23:46

==
а разве select single не эффективнее select ... up to 1 rows ... endselect?
==
Вообще-то на уровень базы данных, эти запросы будут интерпретированы одинаковой командой, поэтому они не могут быть быстрее или медленнее, они на абапе будут написаны по разному, а вот выполняться будут одинаково.

Комментарий от  

Виталий Тарусин

  |  25 октября 2010, 10:11

1) Олег прав, на уровень БД они буду т интерпретированы одинаково, ибо в SQL основных СУБД нет оператора SELECT SINGLE, убедиться в этом можно выполнив трассировку SQL с помощью транзакции ST05
 
2) однако, меня очень удивляет тот факт, что и автор статьи и даже многие разработчики SAP (это видно по исходным текстам) пренебрегают оператором SELECT SINGLE. (Кстати SAP-овцы даже не трудятся приписывать в таких случаях UP TO 1 ROW ! )
На мой взгляд это неэффективное и непрофессиональное использование столь мощного инструмента как ABAP.
 
3) В статье приводятся слишком уж избитые истины и к тому же очень бегло.
Статья получилась ни о чем.
Считаю, что лучше досконально раскрыть один из аспектов оптимизации, например, JOIN или использование FOR ALL ENTRIES OF.
Ведь ньюансов там очень много.
 
И вообще не понятна целевая аудитория.
Если статья предназначалась начинающим абаперам - оценка "4 с минусом" (для начинающих слишком бегло)
Если - для среднего уровня - оценка "3 с минусом" (все и так понятно)
Если - для высокого уровня - "эээ.... а где, собственно, статья" )))
 
П.С.: нисколько не пытаюсь умалить профессионализм автора, это всего лишь моя оценка данной конкретной статьи

Комментарий от  

Виталий Тарусин

  |  25 октября 2010, 10:14

Прошу прощения оценки по 5-бальной системе

Комментарий от  

Денис Мужжухин

  |  25 октября 2010, 12:14

а мне казалось, что все-таки разница между ними есть. да и в SLIN вот, что пишут на эту тему:
 
The SELECT SINGLE is designed to allow a most efficient access to exactly one record of a database table. It requires that you specify the entire primary key in the WHERE condition with AND and EQ (or "="). Then an access to the database is possible, which requires only one communication step between application server and database server.
 
If you did not specify the entire primary key, instead of a direct access on the database server, a "normal" SELECT is performed, which is the same as a SELECT ... UP TO 1 ROWS. In this case, a cursor is opened, a record is read, and the cursor is closed. This requires a number of communication steps between application server and database server.
 
The extended program check provides a warning to inform you that with the mentioned SELECT SINGLE not the expected fast direct access can be performed.

Комментарий от  

Денис Мужжухин

  |  25 октября 2010, 13:53

оказалось, что пишут неправду. up to 1 rows работает быстрее. может от базы зависит? но на MSS по любому критерию шустрее.

Комментарий от  

Михаил Прусов

  |  25 октября 2010, 23:21

Коллеги, спасибо за комментарии.
 
SELECT SINGLE достоин упоминания вне всякого сомнения. Почему он не указан, я постараюсь объяснить в следующем посту. Но думаю интересней будет о самом операторе.
 
Использование SELECT SINGLE должно давать не менее эффективный результат, с т.ч. производительности, чем приведенная в статье конструкция SELECT ... UP TO 1 ROWS. Теоретически выигрыш при SELECT SINGLE, в сравнение с формой SELECT ... UP TO 1 ROWS, возможен, поскольку эта конструкция более очевидная и, следовательно, потенциально менее зависит от силы оптимизирующих механизмов как на уровне системы SAP, так и на уровне БД. На уровне сервера приложения SAP мы можем получить также потенциально более эффективный код, поскольку не требуется накладных расходов на организацию цикла. Однако, по крупному, в обоих случаях, мы совершенно ясно указываем системе, что нам нужна ровно одна запись. А это значит, что с большой долей вероятности обе конструкции будут давать эквивалентный результат. Важными дополнениями к этим рассуждениям будут несколько моментов:
 
* При указании первичного ключа во фразе WHERE интерфейс БД не будет генерировать специальной конструкции (ROWNUMBER, ROWNUM и пр.) для ограничения числа записей. Результирующий оператор будет короче и, следовательно пусть не намного, но оптимальней.
 
* SELECT ... UP TO 1 ROWS позволяет использовать фразу ORDER BY. Это дает нам, в определенных случаях, наиболее оптимальный способ поиска записи с наименьшим/наибольшим значением поля среди набора записей с одинаковым критерием выборки.
 
* Интерфейс БД SAP НЕ ИСПОЛЬЗУЕТ SINGLE-RECORD буфер при использовании конструкции SELECT ... UP TO 1 ROWS, даже если мы укажем полный первичный ключ во фразе WHERE. Это значит, скорость доступ к буферизируемым таблицам может быть на порядки медленней при использовании конструкции SELECT ... UP TO 1 ROWS.

Комментарий от  

Сергей Трапезников

  |  28 октября 2010, 13:24

Использование SELECT ...ENDSELECT уже говорит о том, что программа не оптимизирована.
Вы забыли указать про предпочтительное использование внутренних таблиц для обработки данных, чем
обработку данных через СУБД.
Конструкция SELECT ... ENDSELECT подразумевает обработку данных в цикле, при этом СУБД будет занята на время выполнения всего цикла.
Гораздо предпочтительнее  использовать внутренние таблицы и считывать запрос за один проход
select field1 , field2 into itab
where .... .
а даллее проводить обработку данных в цикле
loop at itab.
endloop.
При таком подходе можно значительно снизить нагрузку на СУБД.

Комментарий от  

Олег Точенюк

  |  28 октября 2010, 15:39

===
Использование SELECT ...ENDSELECT уже говорит о том, что программа не оптимизирована.
===
А кто вам это сказал, что это значит что она не оптимизирована? Или оптимизация по памяти таковой не считается? Ситуации бывают разные, а поэтому сказать что данная конструкция не должна применяться, очень спорное заявление.

Комментарий от  

Сергей Трапезников

  |  02 ноября 2010, 09:25

===
Использование SELECT ...ENDSELECT уже говорит о том, что программа не оптимизирована.
===
А кто вам это сказал, что это значит что она не оптимизирована? Или оптимизация по памяти таковой не считается? Ситуации бывают разные, а поэтому сказать что данная конструкция не должна применяться, очень спорное заявление.
===
 
Безусловно , ситуации бывают разные, иногда бывает дешевле оставить такую конструкцию.
Однако конструкция SELECT ... ENDSELECT при выполнении каких-либо существенных по времени операций в цикле сильно съедает ресурсы БД и подлежит оптимизации в первую очередь. Естественно, на все надо смотреть комплексно, чтобы не влезть в другую крайность.
Оптимизация данной конструкции должна быть достойна внимания не меньше, чем SELECT SINGLE.

Комментарий от  

Анатолий Ермаков

  |  03 ноября 2010, 13:16

===
Оптимизация данной конструкции должна быть достойна внимания не меньше, чем SELECT SINGLE.
===
Решение об оптимизации должно приниматься на основе измерений, а не использовния каких-либо конструкций в коде.
Для разных БД и версий системы результаты могут быть отличаться.

Комментарий от  

Михайлович Леонид

  |  10 августа 2017, 16:48

Порекомендовал бы создавать индексы по полям в клаузе WHERE. Выборка будет значительно быстрее, также рекомендую не использовать в WHERE конструкцию <>(не равно).

Комментарий от  

Олег Точенюк

  |  11 августа 2017, 13:57

Порекомендовал бы создавать индексы по полям в клаузе WHERE. Выборка будет значительно быстрее, также рекомендую не использовать в WHERE конструкцию <>(не равно).

С индексами спорное утверждение. Любой индекс это увеличение БД и времени вставки записей данных в БД. Так же есть вероятность, что ваш новый индекс нарушит работу других программ, так как поменяет план запроса, после чего чужие программы станут работать медленнее, ну если там индексы гвоздями не прибили в запросах (что является редким). Так что создавать индексы можно, но делать это каждый раз, сильно не рекомендуется, а то у вас накладные расходы на подержание индексов могут превысить их пользу в скорости выборки.

Комментарий от  

Олег Точенюк

  |  11 августа 2017, 13:59

Порекомендовал бы создавать индексы по полям в клаузе WHERE. Выборка будет значительно быстрее, также рекомендую не использовать в WHERE конструкцию <>(не равно).

А ну и это, про не равно в статье есть: "Пытайтесь избегать использование отрицания NOT во фразе WHERE. Отрицание не может быть обработано с помощью индекса."