Oracle
 sql >> Base de données >  >> RDS >> Oracle

Une syntaxe pour l'évaluation paresseuse personnalisée/le court-circuit des paramètres de fonction

L'évaluation paresseuse peut être (partiellement) implémentée à l'aide de curseurs de référence, d'une compilation conditionnelle ou d'une exécution immédiate. Le type ANYDATA peut être utilisé pour transmettre des données génériques.

Curseur de référence

Les curseurs de référence peuvent être ouverts avec une instruction SQL statique, transmise en tant qu'arguments, et ne s'exécuteront pas tant que cela n'est pas nécessaire.

Bien que cela réponde littéralement à votre question sur l'évaluation paresseuse, je ne sais pas si c'est vraiment pratique. Ce n'est pas l'utilisation prévue des curseurs de référence. Et il n'est peut-être pas pratique d'avoir à ajouter SQL à tout.

Tout d'abord, pour prouver que la fonction lente est en cours d'exécution, créez une fonction qui dort simplement pendant quelques secondes :

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;
/

Créez une fonction pour déterminer si une évaluation est nécessaire :

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

Cette fonction peut effectuer le travail en exécutant l'instruction SQL. L'instruction SQL doit renvoyer quelque chose, même si vous ne souhaitez pas de valeur de retour.

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;
/

Créez maintenant la procédure qui appellera toujours trace mais ne passera pas nécessairement de temps à évaluer les arguments.

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;
/

Par défaut, il fait le travail et est lent :

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

Mais lorsque vous modifiez DO_I_HAVE_TO_TRACE pour retourner false la procédure est rapide, même si elle passe un argument lent.

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;
/

Autres options

La compilation conditionnelle est plus traditionnellement utilisée pour activer ou désactiver l'instrumentation. Par exemple :

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;
/

Vous voudrez peut-être également reconsidérer le SQL dynamique. Le style de programmation et un peu de sucre syntaxique peuvent faire une grande différence ici. En bref, la syntaxe alternative des guillemets et les modèles simples peuvent rendre le SQL dynamique beaucoup plus lisible. Pour plus de détails, voir mon article ici .

Transmettre des données génériques

Les types ANY peuvent être utilisés pour stocker et transmettre n'importe quel type de données imaginable. Malheureusement, il n'y a pas de type de données natif pour chaque type de ligne. Vous devrez créer un TYPE pour chaque table. Ces types personnalisés sont très simples afin que cette étape puisse être automatisée si nécessaire.

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;
/