문제

내가 함수 호출이 있다고 가정 해 봅시다. 고르다 또는 어디 다음과 같은 Oracle의 조항 :

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

MS SQLServer에 대해 유사한 예제를 구성 할 수 있습니다.

각 경우에 예상되는 행동은 무엇입니까?

입니다 해시시 기능은 테이블의 각 행에 대해 한 번 호출되거나 DBMS는 함수를 한 번만 호출 할 수있을 정도로 스마트합니다. 부작용?

정말 감사합니다.

도움이 되었습니까?

해결책

Oracle의 대답은 그것이 달라집니다. 함수가 '결정 론적'으로 표시되지 않는 한 선택된 모든 행에 대한 함수는 한 번만 호출됩니다.

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;

산출:

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

3 rows selected


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

1 rows selected

따라서 StringLen () 함수는 첫 번째 경우에서 세 번 호출되었습니다. 이제 결정 론적으로 표시되는 StringLen2 ()로 실행할 때 :

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;

결과:

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

3 rows selected

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

1 rows selected

따라서 StringLen2 () 함수는 결정 론적으로 표시 되었기 때문에 한 번만 호출되었습니다.

결정 론적으로 표시되지 않은 함수의 경우 다음과 같은 쿼리를 수정하여이를 해결할 수 있습니다.

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

다른 팁

SQL Server의 경우 모든 행에 대해 평가됩니다.

함수를 한 번 실행하고 변수에 할당하고 쿼리의 변수를 사용하여 훨씬 나을 것입니다.

짧은 대답 .... 그것은 달라집니다.

함수가 데이터에 액세스하는 경우 Oracle은 각 행마다 동일 할 것인지 알지 못하므로 각각에 대해 쿼리해야합니다. 예를 들어, 기능이 항상 동일한 값을 반환하는 형성자 인 경우 캐싱 (결정 론적으로 표시)을 켜면 기능 호출 만 한 번만 수행 할 수 있습니다.

당신이보고 싶은 것은 하위 퀘스트가있는 Oracle입니다.

with query_name clause를 사용하면 이름을 하위 쿼리 블록에 할당 할 수 있습니다. 그런 다음 쿼리 이름을 지정하여 쿼리에서 하위 쿼리 블록 여러 장소를 참조 할 수 있습니다. Oracle은 쿼리 이름을 인라인보기 또는 임시 테이블로 취급하여 쿼리를 최적화합니다.

인용 된 텍스트를 받았습니다 여기, 많은 예가 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top