SQL에서 처음 실행되는 함수에 의존 할 수 있습니까


9

다음 스크립트를 고려하십시오.

create or replace function f(p_limit in integer) return integer as
begin
  set_global_context ('limit', p_limit);
  return p_limit;
end;
/

create view v as 
select level as val from dual connect by level<=sys_context('global_context','limit');

select f(2), v.* from v;

/*
F(2)                   VAL                    
---------------------- ---------------------- 
2                      1                      
2                      2                      
*/

select f(4), v.* from v;

/*
F(4)                   VAL                    
---------------------- ---------------------- 
4                      1                      
4                      2                      
4                      3                      
4                      4                      
*/

f(x)10.2에서 실행 된이 테스트 케이스에서와 같이 뷰 내에서 컨텍스트를 읽기 전에 실행 에 의존 할 수 있습니까 ?


도움이 될 수는 없지만 로그인 트리거가 더 적절하다고 생각할 수 있습니다 (레벨이 항상 같을 경우)
Philᵀᴹ

@Phil 이것은 단지 예일뿐입니다-sys_context를 사용하여 뷰를 매개 변수화하고 매번 매개 변수가 달라집니다. 이런 식으로 SQL에서 전역 컨텍스트를 설정하는 방법을 알고 있다면 그 소식을 듣고 싶습니다.
잭 topanswers.xyz 시도라고

1
@ JackDouglas : 매개 변수보기는 나에게 "느끼지"않는 아이디어입니다. MSSQL에서 수행하려는 작업은 값이 아닌 결과 집합을 반환하는 사용자 정의 함수를 사용하여 수행 할 수 있습니다 SELECT stuff FROM dbo.FuncReturningTable(param). 오라클은 아마도 동등한 기능을 가지고 있습니다. 대용량 데이터 세트에서 이것을 사용하는 경우 성능을 모니터 할 때주의해야합니다. 쿼리 플래너가 그러한 구문에서 효율적인 계획을 세우는 데 얼마나 밝은 지 확신 할 수 없습니다.
David Spillett

뷰를 올리는 @David 매개 변수는 일반적으로 sys_context를 사용하여 수행됩니다. 일반적으로 쿼리를 실행하기 전에 컨텍스트를 설정합니다 (예 : 약간의 PL / SQL). 오라클은 set-returning 및 / 또는 파이프 라인 기능을 가지고 있지만 이것을 달성하는 '정상적인'방법은 아닙니다. 분명히, 나는 제목의 질문에 대한 대답이 "아니오"라고 생각합니다. 누군가가 더 잘 알고 있는지 궁금했습니다.
잭 topanswers.xyz 시도라고

답변:


8

아니.

connect by 대신 where 절에 대한 컨텍스트 필터링으로 뷰를 다시 작성하면 컨텍스트에 대해 이전에 설정된 값을 얻습니다.

create table t as 
 select rownum r from dual connect by level <= 10;

create or replace view v as 
  select r val from t where r <=sys_context('global_context','limit');

select f(2), v.* from v;

F(2) VAL
---- ---
   2   1 
   2   2 

select f(4), v.* from v;

F(4) VAL
---- ---
   4   1 
   4   2 

select f(4), v.* from v;

F(4) VAL
---- ---
   4   1 
   4   2 
   4   3 
   4   4 

열을 선택하기 전에 where 절이 평가되므로 컨텍스트를 읽은 후에야 함수에 전달 된 값이 설정되지 않습니다. 쿼리에서 sys_context 호출의 위치 (선택, 위치, 그룹 별 등)는이 값이 설정 될 때 정확하게 영향을 미칩니다.


+1 그것은 내 책에서 거의 "사건 폐쇄"입니다. 감사합니다.
잭 topanswers.xyz 시도라고

2

일반적으로 단일 SQL 문을 평가할 때 DBMS가 수행하는 순서에 대해서는 안전하게 가정 할 수 없습니다. 이것이 많은 DBMS가 부작용을 갖는 방식으로 사용되는 함수를 허용하지 않는 이유입니다 (즉, MSSQL은 함수가 전역 / 연결 상태를 설정하거나 테이블 내용을 변경하는 것을 허용하지 않습니다). 일련의 명령문은 한 단계에서 다음 단계로 이해되는 방식으로 실행되어야합니다 (즉, 순차적으로 실행되거나 그렇지 않다는 것을 알 수없는 방식으로 실행). 그러나 단일 명령문 내에서 쿼리 플래너 이미 존재하지 않는 곳에서 모호성을 도입하지 않는 한 자유 통치권을 가지고 있습니다 (예를 들어, 기능에 부작용이있어서 모호성이 이미 존재합니다).

쿼리 플래너가 뷰가 함수의 부작용에 의해 영향을 받는다는 것을 감지 할 수있을 정도로 밝다면, 다른 입력 값으로 해당 함수를 호출 한 다른 뷰에 참여하면 어떻게됩니까? 그것은 매우 빨리 털이 될 수 있습니다-이런 종류의 일은 일반적으로 어떤 프로그래밍 상황에서도 함수가 자신의 출력을 넘어서는 영향을 미치지 않아야하는 이유입니다.

이 특정 예제에서 나는 문장의 일부를 "표시"하기 때문에 f (x)가 먼저 호출되지는 않을 것이라고 말하고 싶습니다 : 뷰의 결과 세트는 반환 할 열 목록이 평가됩니다. 물론 이것은 사용되는 DBMS에 따라 다릅니다. Oracle 전문가가 아니며 테스트 결과에 따르면 이러한 인스턴스에서 함수가 먼저 호출되는 것으로 보입니다. 그러나 단일 SQL 문 내에서 실행 순서에 모두 똑같이 의존하는 것에 대해 조심할 것입니다. 항상 현재 예상대로 작동하더라도 향후 개정에서는 그렇지 않을 수 있습니다 (공식적으로 실행이 진행되는 곳에서 공식적으로 문서화되지 않는 한) 이런 식으로).


2
좋은 답변이지만 Jack이 확실한 기술적 인 Oracle 답변을 찾고 있다고 생각합니다.
Philᵀᴹ

1

이 문서는 "최적화 프로그램은 먼저 상수를 포함하는 표현식과 조건을 가능한 한 완벽하게 평가합니다"라고 약속합니다. ( 10.2 , 11.2 ). 특정 표현식을 먼저 평가하거나 때때로 그 순서를 변경하지 않는다고 보장하지는 않습니다 (동일한 릴리스 내의 새로운 패치 레벨?).


+1 우수, 감사 (내 그 문서를 읽기에 불구하고 꽤 사각형하지 않는 크리스의 대답 )
잭은 말한다 topanswers.xyz 시도

1
차이점은 함수가 where, select 또는 다른 절에서 호출되는지 여부입니다. 선택 섹션의 함수는 최적화 프로그램 결정 (하위 쿼리가 아닌 경우)에 영향을 미치지 않으므로 결과를 페치 할 때까지 평가할 필요가 없습니다. where 절의 함수는 사용 된 조인 메소드에 영향을 미치므로 가능한 빨리 평가해야합니다.
크리스 색슨

@Chris는 그 경험에 대한 이야기입니까, 아니면 어딘가에서 문서에서 얻었습니까?
잭 topanswers.xyz 시도라고

문서 참조를 찾을 수 없습니다. 내 경험에 따르면, where 테이블에서 단일 테이블을 필터링하기 위해 호출되면 모든 행 (FTS 가정)에 액세스하지만 선택 목록에있는 경우 반환되는 행에 대해서만 액세스됩니다. 구문 분석 중에 실행 계획이 설정되었으므로 select의 함수가 영향을 미치지 않습니다. 이를 확인하기위한 테스트 케이스는 카운터를 설정하는 함수 (패키지 또는 테이블에서)를 만들고 쿼리의 위치에 따라 출력을 비교하여 수행 할 수 있습니다.
크리스 색슨
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.