Frage

Lassen Sie uns sagen, ich habe einen Funktionsaufruf auf eine wählen oder Dabei gilt: Klausel in Oracle wie folgt aus:

select a, b, c, dbms_crypto.hash(utl_raw.cast_to_raw('HELLO'),3)
  from my_table

Ein ähnliches Beispiel kann für MS SQL Server aufgebaut werden.

Was ist das erwartete Verhalten in jedem Fall?

Ist der HASH gehen Funktion aufgerufen für jede Zeile in der Tabelle einmal werden, oder wird DBMS intelligent genug sein, um die Funktion aufzurufen, nur einmal, da es sich um eine Funktion mit konstanten Parametern ist und keine Nebenwirkungen

Vielen Dank.

War es hilfreich?

Lösung

Die Antwort für Oracle ist es hängt davon ab. Die Funktion wird für jede Zeile ausgewählt genannt werden, wenn die Funktion markiert ist ‚deterministisch‘ in diesem Fall wird es nur einmal aufgerufen werden.

CREATE OR REPLACE PACKAGE TestCallCount AS
    FUNCTION StringLen(SrcStr VARCHAR) RETURN INTEGER;
    FUNCTION StringLen2(SrcStr VARCHAR) RETURN INTEGER DETERMINISTIC;
    FUNCTION GetCallCount RETURN INTEGER;
    FUNCTION GetCallCount2 RETURN INTEGER;
END TestCallCount;

CREATE OR REPLACE PACKAGE BODY TestCallCount AS
    TotalFunctionCalls INTEGER := 0;
    TotalFunctionCalls2 INTEGER := 0;

    FUNCTION StringLen(SrcStr VARCHAR) RETURN INTEGER AS
    BEGIN
        TotalFunctionCalls := TotalFunctionCalls + 1;
        RETURN Length(SrcStr);
    END;
    FUNCTION GetCallCount RETURN INTEGER AS
    BEGIN
        RETURN TotalFunctionCalls;
    END;

    FUNCTION StringLen2(SrcStr VARCHAR) RETURN INTEGER DETERMINISTIC AS
    BEGIN
        TotalFunctionCalls2 := TotalFunctionCalls2 + 1;
        RETURN Length(SrcStr);
    END;
    FUNCTION GetCallCount2 RETURN INTEGER AS
    BEGIN
        RETURN TotalFunctionCalls2;
    END;

END TestCallCount;




SELECT a,TestCallCount.StringLen('foo') FROM(
    SELECT 0 as a FROM dual
    UNION
    SELECT 1 as a FROM dual
    UNION
    SELECT 2 as a FROM dual
);

SELECT TestCallCount.GetCallCount() AS TotalFunctionCalls FROM dual;

Ausgabe:

A                      TESTCALLCOUNT.STRINGLEN('FOO') 
---------------------- ------------------------------ 
0                      3                              
1                      3                              
2                      3                              

3 rows selected


TOTALFUNCTIONCALLS     
---------------------- 
3                      

1 rows selected

So ist die StringLen () Funktion dreimal im ersten Fall genannt wurde. Nun, wenn sie mit StringLen2 Ausführung (), die deterministisch bezeichnet wird:

SELECT a,TestCallCount.StringLen2('foo') from(
    select 0 as a from dual
    union
    select 1 as a from dual
    union
    select 2 as a from dual
);

SELECT TestCallCount.GetCallCount2() AS TotalFunctionCalls FROM dual;

Ergebnisse:

A                      TESTCALLCOUNT.STRINGLEN2('FOO') 
---------------------- ------------------------------- 
0                      3                               
1                      3                               
2                      3                               

3 rows selected

TOTALFUNCTIONCALLS     
---------------------- 
1                      

1 rows selected

So ist die StringLen2 () Funktion nur einmal aufgerufen wurde, da es deterministisch markiert wurde.

Für eine Funktion nicht deterministisch markiert, können Sie dieses Problem umgehen, indem Sie Ihre Abfrage als solche ändern:

select a, b, c, hashed
  from my_table
cross join (
  select dbms_crypto.hash(utl_raw.cast_to_raw('HELLO'),3) as hashed from dual
);

Andere Tipps

Für SQL-Server, wird es für jede einzelne Zeile ausgewertet werden.

Sie werden viel besser durch die Funktion einmal ausgeführt wird und eine Variablen zugewiesen und die Variable in der Abfrage verwendet wird.

kurze Antwort .... es hängt davon ab.

Wenn die Funktion auf Daten zugreift ORACLE weiß nicht, ob es das gleiche für jede Reihe sein wird, daher muss es für jeden abzufragen. Wenn zum Beispiel Ihre Funktion ist nur eine Formatierer, die immer den gleichen Wert zurückgibt, dann können Sie auf Caching drehen (Markierung als deterministische), die erlauben kann für Sie nur einmal den Funktionsaufruf zu tun.

Etwas, das Sie in aussehen wollen können ORACLE MIT Unterabfrage ist:

  

Die WITH QUERY_NAME Klausel können Sie   einen Namen einer Unterabfrage Block zuweisen. Sie   Referenz kann dann die Unterabfrage Blockes   mehrere Orte in der Abfrage durch   Angabe der Abfragenamen. Orakel   optimiert die Abfrage durch die Behandlung   Abfragenamen entweder als ein Inline-View oder   als eine temporäre Tabelle

Ich habe den zitierten Text von hier , die viele Beispiele hat.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top