PL/SQL Native Compilation - "разгон" выполнения хранимых процедур
Oracle Database версии 11g, помимо множества новых возможностей и улучшений, принесла еще одну замечательную технологию - PL/SQL Native Compilation.
Мне думается, что у большинства читателей этого блога для реализации бизнес-логики активно используется именно PL/SQL, и многие "ломают" голову над тем, как заставить свой код выполняться быстрее... :-)
Существует два варианта компиляции ваших хранимых процедур PL/SQL:
- interpreted (в результате из исходного кода процедуры получается интерпретируемый код виртуальной машины PL/SQL);
- native (в результате компиляции на выходе получается исполняемый код текущей платформы).
Понятно, что в втором случае достигается максимальная скорость выполнения хранимой процедуры, поскольку отсутсвует фаза интерпетации кода виртуальной машины PL/SQL (как в первом случае), и код напрямую выполняется на процессоре.
Возможность компиляции кода процедуры была доступна еще начиная с версии 9.2 , но она была реализована через генерацию промежуточного C-кода, с последующей его компиляцией в нативный код платформы. Это создавало массу неудобств:
- нужно лицензировать и устанавливать C-компилятор;
- после линковки объектного модуля на выходе получался большой по размеру файл разделяемой библиотеки (dll,so,sl, ...), потому-что линкер честно "запихивал" в каждый модуль runtime-библиотеку C.
С второй проблемой можно было бороться двумя способами: динамической линковкой стандартных runtime-библиотек C, либо "обезжириванием" этих библиотек через правку исходников (что требует серьезной "сишной" квалификации и в общем случае чревато проблемами).
Лично мой опыт показал, что для получения максимального выигрыша от этой технологии мне потребуется сделать редизайн и перегруппировку своего PL/SQL-кода, что было невозможно по временным и ресурсным ограничениям. Я использовал платформу Windows и компилятор Visual C. После компиляции получались dll-файлы неприличных размеров - выполняемый код "разбухал".
Вообщем: Native Compilation не пользовался успехом у разработчиков и администраторов.
Но теперь все это позади - начиная с 11-ой версии, компилятор PL/SQL может генерировать исполняемый код на "лету", - нет необходимости ставить и настраивать С-компилятор.
Все что для этого нужно: это установить параметр PLSQL_CODE_TYPE в значение NATIVE, и после этого перекомпилировать процедуры.
Какой выигрыш в скорости выполнения обеспечивает native-компиляция PL/SQL ?
Все зависит от вашего PL/SQL-кода: если в нем много логики, но мало обращения к БД (к SQL-движку), то скорость возрастает в разы! Если наоборот, весь код состоит из оператов SQL, то выигрыш конечно будет небольной, - обращения к СУБД "съедают" львиную долю времени выполнения.
В большинстве случаев код имеет смешанный характер, то есть состоит из вычислительной обработки и операторов SQL. Nаtive Compilation даже в этом случае дает существенный выигрыш в производительности. Конечно, реальный коэффициент ускорения может быть получен только после тестов на конкретном приложении.
В случае принятия решения об использовании PL/SQL Native Complilation рекомендуется целиком перекомпилировать весь PL/SQL в СУБД. В документации по PL/SQL приведена подробная инструкция как это сделать: Compiling the Entire Database for PL/SQL Native or Interpreted Compilation
Недавно в одном из проектов я попробовал эту технологию. Код приложения состоял примерно из 3 млн. строк кода PL/SQL. Код приложения хорошо структурирован и состоит из небольших процедур сгруппированных по пакетам, поэтому дополнительно я включил третий уровень оптимизации PL/SQL (параметр PLSQL_OPTIMIZE_LEVEL=3).
По результатам тестов - скорость выполнения увеличилась примерно в три раза !
Хочу поделиться некоторыми наблюдениями:
- время компиляции в Native-режиме сильно замедляется (на моем 2-хпроцессорном сервере с 2 Xeon Nehalem перекомпиляция всей СУБД заняла около 4 чаcов!), поэтому ее не рекомендуется включать на development-среде;
- возрастают требования к памяти - выполняемый код больше по объему, чем код PL/SQL VM (в моем случае процентов на 10-15, но скорее всего это из-за inline-подстановки);
- при выполнении native-скомпилированных процедур возрастает утилизация процессоров, поэтому при переходе в этом режим нужно иметь запас в CPU, на мой взгляд - минимум процентов на 20-30.
По-моему PL/SQL native compilation очень интересная возможность Oracle Database 11g - почему бы ее не использовать ?
P.S. Поделилтесь, пожалуйста, в комментариях к этому посту о своем опыте использования этой технологии.
Я пробовал нативно компилить PL/SQL Web Toolkit (aka OWA), получилось не слишком заметно - порядка +10% RPS на генерации статической странички через htp.p(). Другое дело, что на Xeon 5345 (HP DL 360G5) в абсолютных цифрах это было порядка и так 8000 RPS, если стрелять по Apache + mod_owa.
ОтветитьУдалитьМы протестировали и использовали указанную возможность (выполнение внешней процедуры на языке С)
ОтветитьУдалитьна Оракл 9.2.х, 10.1.х, 10.2.х. для ускорения процедуры расчета, написанной сначала на PL\SQL
и выполняемой в цикле многократно (сотни тысяч раз). Как недостаток – наличие больших сложностей
при компилировании «сишным» компилятором DLL-библиотеки под различные платформы Windows (x86, x64)
и процессоры (Itanium, AMD). Тут стоит сказать о намного более «легком» получении shared object
под Linux платформу (Red Hat) - создать нужный make файл оказалось намного проще.
(Тестировали на 11g при дефолтовом значении параметра PLSQL_OPTIMIZE_LEVEL=2.)
Проведенные тесты показали различную скорость выполнения одной и той же процедуры на языках С,
Java (как вызываемых внешних процедур) и PL\SQL для разных версий БД и режимов компиляции.
Скорость выполнения внешней процедуры на C и Java ориентировочно
в два раза выше, чем процедуры на PL\SQL для БД Oracle 9iR2.
В случае БД Оракл 10gR2, 11gR1, 11gR2 время выполнения кода на PL\SQL сократилось в 2.5-3 раза,
относительно времени, затраченного на выполнения внешних процедур на языках C и Java.
При этом режим Nаtive Compilation быстрее приблизительно на 25-30% от режима INterpreted Compilation
для версий БД 10gR2, 11gR1, 11gR2. Процедуры, написанные на C и Java, практически близкие по времени
выполнения между собой, это время практически не зависит от режима компиляции Nаtive или INterpreted.
Отсюда выводы (для данного конкретного случая):
1) выполнение PL\SQL кода значительно ускорено в версиях 10g и 11g по сравнению с 9i (в 5-10 раз);
2) внешние процедуры на C и Java проигрывают по скорости PL\SQL в 2 и более раза на 10gR2, 11g(R1,R2);
3) при включении режима Nаtive Compilation на сессию скорость тестируемой процедуры на PL\SQL увеличилась
приблизительно на одну треть относительно режима Interpreted Compilation.
Данные сведены в две таблицы:
ОтветитьУдалитьТабл.1 - Oracle DB: INterpreted Compilation
Табл.2 - Oracle DB: Nаtive Compilation
Сокращения ОС:
L - Linux RHAS rel.4 Nehalem 64-bit;
W - Windows XP SP3 32-bit.
Табл.1. INTERPRETED COMPILATION (ORACLE DB)
-------------------------------------------------------------------
Cycles 5000 50000 500000 5000000
(times in seconds)
-------------------------------------------------------------------
Oracle DB 9iR2 (L): - PL\SQL 0.953 8.656 87.282 835.531
- Java 0.500 4.594 44.109 437.984
- C 0.500 4.641 48.453 457.125
Oracle DB 10gR2 (L):- PL\SQL 0.203 1.656 16.484 165.500
- Java 0.422 4.094 40.235 410.895
- C 1.938 4.890 51.265 529.219
Oracle DB 11gR1 (W):- PL\SQL 0.125 1.031 10.203 102.187
- Java 0.125 1.328 13.203 131.266
Oracle DB 11gR2 (L):- PL\SQL 0.359 1.735 12.391 109.859
- Java 0.484 1.844 18.766 178.484
- C 0.562 5.500 50.703 406.985
-------------------------------------------------------------------
Табл.2. NATIVE COMPILATION (ORACLE DB)
-------------------------------------------------------------------
Cycles 5000 50000 500000 5000000
Program (times in seconds)
-------------------------------------------------------------------
Oracle DB 10gR2 (L):- PL\SQL 0.156 1.531 15.360 153.109
- Java 0.422 4.140 41.963 415.719
- C 0.500 4.875 52.735 513.407
Oracle DB 11gR1 (W):- PL\SQL 0.094 0.688 6.790 67.828
- Java 0.203 1.313 13.219 132.219
Oracle DB 11gR2 (L):- PL\SQL 0.172 1.172 8.500 71.891
- Java 0.344 2.297 18.125 179.976
- C 0.672 5.547 44.141 385.125
-------------------------------------------------------------------
К выводам вдобавок (к выполнению конкретной процедуры на PL\SQL):
ОтветитьУдалить4) Interpreted Compilation в 11g (оказался в этом случае) быстрее чем в 10g в 1.5 раза.
5) Native Compilation в 11g оказался быстрее чем в 10g в 2.1 раза.
Игорь, а можете опубликовать исходный код, от которого данные Ваших тестов? Смущает медленное выполнение на C. Первое, что приходит в голову - тормозит в extproc IPC передачей большого объёма параметров туда/обратно.
ОтветитьУдалить> Oracle Database версии 11g, помимо множества новых возможностей и улучшений, принесла еще одну замечательную технологию - PL/SQL Native Compilation.
ОтветитьУдалитьНе скажу точно на счет 9-й версии, но в 10g Native Compilation точно есть. Поэтому, фича хорошая, нужная, но никак не новая.
>>Игорь, а можете опубликовать исходный код, от которого данные Ваших тестов?
ОтветитьУдалитьКак таковых отдельных тестов не было.
Это было воспроизведение реальной нагрузки с помощью RAT (Real Application Testing) на копии большой производственной БД заказчика.
Да действительно: External Library медленнее, поскольку нужно передавать параметры отдельному процессу.
Еще конечно нужно "поколдовать" с опциями C-компилятора (убрать ненужные runtime-проверки и включить оптимизацию).
>>Не скажу точно на счет 9-й версии, но в 10g Native Compilation точно есть.
ОтветитьУдалитьДа - технология не новая. Но теперь реализована по другому, и избавлена от недостатков старых версий.
вместе с OLS получается баг 9869915
ОтветитьУдалить