sql >> Base de Datos >  >> RDS >> Oracle

Una sintaxis para evaluación perezosa personalizada/cortocircuito de parámetros de función

La evaluación diferida se puede implementar (parcialmente) usando cursores de referencia, compilación condicional o ejecución inmediata. El tipo ANYDATA se puede usar para pasar datos genéricos.

Cursor de referencia

Los cursores de referencia se pueden abrir con una instrucción SQL estática, se pueden pasar como argumentos y no se ejecutarán hasta que se necesiten.

Si bien esto responde literalmente a su pregunta sobre la evaluación perezosa, no estoy seguro de si es realmente práctico. Este no es el uso previsto de los cursores de referencia. Y puede que no sea conveniente tener que agregar SQL a todo.

Primero, para probar que la función lenta se está ejecutando, cree una función que simplemente duerma durante unos segundos:

grant execute on sys.dbms_lock to <your_user>;

create or replace function sleep(seconds number) return number is
begin
    dbms_lock.sleep(seconds);
    return 1;
end;
/

Cree una función para determinar si la evaluación es necesaria:

create or replace function do_i_have_to_trace return boolean is
begin
    return true;
end;
/

Esta función puede realizar el trabajo ejecutando la instrucción SQL. La instrucción SQL debe devolver algo, aunque es posible que no desee un valor de retorno.

create or replace procedure trace_something(p_cursor sys_refcursor) is
    v_dummy varchar2(1);
begin
    if do_i_have_to_trace then
        fetch p_cursor into v_dummy;
    end if;
end;
/

Ahora cree el procedimiento que siempre llamará al rastreo pero que no necesariamente dedicará tiempo a evaluar los argumentos.

create or replace procedure lazily_trace_something(some_number in number) is
    v_cursor sys_refcursor;
begin
    open v_cursor for select sleep(some_number) from dual;
    trace_something(v_cursor);
end;
/

Por defecto está haciendo el trabajo y es lento:

--Takes 2 seconds to run:
begin
    lazily_trace_something(2);
end;
/

Pero cuando cambias DO_I_HAVE_TO_TRACE para devolver falso, el procedimiento es rápido, aunque pasa un argumento lento.

create or replace function do_i_have_to_trace return boolean is
begin
    return false;
end;
/

--Runs in 0 seconds.
begin
    lazily_trace_something(2);
end;
/

Otras opciones

La compilación condicional se usa más tradicionalmente para habilitar o deshabilitar la instrumentación. Por ejemplo:

create or replace package constants is
    c_is_trace_enabled constant boolean := false;
end;
/

declare
    v_dummy number;
begin
    $if constants.c_is_trace_enabled $then
        v_dummy := sleep(1);
        This line of code does not even need to be valid!
        (Until you change the constant anyway)
    $else
        null;
    $end
end;
/

También es posible que desee volver a considerar SQL dinámico. El estilo de programación y algo de azúcar sintáctico pueden marcar una gran diferencia aquí. En resumen, la sintaxis de comillas alternativa y las plantillas simples pueden hacer que el SQL dinámico sea mucho más legible. Para obtener más detalles, consulte mi publicación aquí .

Transmisión de datos genéricos

Los tipos ANY se pueden usar para almacenar y pasar cualquier tipo de datos imaginable. Desafortunadamente, no hay un tipo de datos nativo para cada tipo de fila. Deberá crear un TIPO para cada tabla. Esos tipos personalizados son muy simples, por lo que ese paso se puede automatizar si es necesario.

create table some_table(a number, b number);
create or replace type some_table_type is object(a number, b number);

declare
    a_rowtype_variable some_table_type;
    v_anydata anydata;
    v_cursor sys_refcursor;
begin
    a_rowtype_variable := some_table_type(1,2);
    v_anydata := anydata.ConvertObject(a_rowtype_variable);
    open v_cursor for select v_anydata from dual;
    trace_something(v_cursor);
end;
/