쿼리의 Oracle 및 SQLServer 기능 평가
-
06-07-2019 - |
문제
내가 함수 호출이 있다고 가정 해 봅시다. 고르다 또는 어디 다음과 같은 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은 쿼리 이름을 인라인보기 또는 임시 테이블로 취급하여 쿼리를 최적화합니다.
인용 된 텍스트를 받았습니다 여기, 많은 예가 있습니다.