Как прагма UDF работает?

Недавно прочёл о методе оптимизации с прагмой UDF в версии 12c.

Интересуюсь, как же это в точности работает. Нашёл только очень короткое описание в оф. документации:

The UDF pragma tells the compiler that the PL/SQL unit is a user defined function that is used primarily in SQL statements, which might improve its performance.

Как я понял, каждая прагма в PL/SQL это своего рода деректива компилятору (но точно не уверен) подобная C++ Pragma Directives.

Может кто-то более детально объяснить, какой внутренний механизм работы UDF прагмы?


Свободный перевод How Pragma UDF works? от участника @Oiale


Ответы (2 шт):

Автор решения: 0xdb

Внутренние детали работы компилятора PL/SQL нам не доступны, но в основном, прагма UDF это деректива компилятору, что нужно уделить больше внимания снижению затрат на переключение контекста вызова между PL/SQL и SQL.

Смею предположить, что эта прагма пользуется тем же преимущестом, которое получили PL/SQL функции напрямоую встроенные в CTE (Common Table Expression), например:

WITH function myfunction(x int) return int as
    begin
        return x;
    end;
select myfunction (n) from mytable

PL/SQL функции как показано выше, действуют на время выполнения SQL запроса, выполняются с повышенными характеристиками производительности по сравнению с обычными сохранёнными функциями. Подозреваю, что UDF прагма позволяет пустить выполненение обычной PL/SQL функцию тем же путём, каким и выполняются встроенные в CTE.

(Но это мои личные предположения).


Свободный перевод ответа от участника @Connor McDonald

→ Ссылка
Автор решения: 0xdb

В документации в гл. 2.2.4 Pragmas сказано буквально следующее:

A pragma is an instruction to the compiler that it processes at compile time.

Oracle БД это продукт с закрытым кодом, поэтому больше чем написано в документации или получено опытым путём, о внутренних механизмах работы неизвестно.

Цель UDF прагмы - приблизить быстродействие пользовательских PL/SQL функций (UDF - user defined function) выполлняемых в основном в SQL контексте к нативно встроенным в SQL интерпретатор.


Фразу из документации - which might improve its performance, следует понимать буквально - может улучшить производительность, а может и нет. В различных блогах можно найти тесты, которые с различной комбинацией типов данных параметров и возврата не привели к ожидаемому приросту производительности. Предложение об улучшении уже поступило, когда будет реализовано - пока неясно.

Лучше убедится на конкретной функции, есть ли прирост производительности, например так:

create or replace function plspow2 (n number) return number is
begin return power (n, 2); end;
/
create or replace function udfpow2 (n number) return number is
    pragma udf;
begin return power (n, 2); end;
/
create table t2 as
    select level n from dual connect by level<=10e5;

declare
    t number; c number; r number;
begin 
    t := dbms_utility.get_time;
    c := dbms_utility.get_cpu_time;
    select count(*) into r from t2 where n < power (n, 2);
    dbms_output.put_line ('native SQL elapsed '||(dbms_utility.get_time-t)||' cpu '||(dbms_utility.get_cpu_time-c));
    t := dbms_utility.get_time;
    c := dbms_utility.get_cpu_time;
    select count(*) into r from t2 where n < plspow2 (n);
    dbms_output.put_line ('normal PLS elapsed '||(dbms_utility.get_time-t)||' cpu '||(dbms_utility.get_cpu_time-c));
    t := dbms_utility.get_time;
    c := dbms_utility.get_cpu_time;
    select count(*) into r from t2 where n < udfpow2 (n);
    dbms_output.put_line ('pragma UDF elapsed '||(dbms_utility.get_time-t)||' cpu '||(dbms_utility.get_cpu_time-c));
end;
/
native SQL elapsed 49 cpu 49
normal PLS elapsed 368 cpu 367
pragma UDF elapsed 100 cpu 100

Elapsed: 00:00:05.219
→ Ссылка