programing

Oracle SQL: 인라인 뷰에 있을 때 SYS_GUID()의 동작을 이해하시겠습니까?

bestprogram 2023. 7. 6. 22:25

Oracle SQL: 인라인 뷰에 있을 때 SYS_GUID()의 동작을 이해하시겠습니까?

다음은 문제의 SQL 예제입니다.SQL은 모든 Oracle DBMS에서 실행되어야 합니다(11.2.0.2.0 실행 중).

인라인 뷰/with 절 내에서 빌드되었음에도 불구하고 결과 집합에서 UUID 값이 어떻게 다른지(하나는 898개이고 다른 하나는 899개임)에 주목합니다.아래에서 DBMS_RANDOM.RANDOM()이 이러한 부작용을 일으키지 않는 방법을 확인할 수 있습니다.

SQL:

WITH data AS (SELECT SYS_GUID () uuid FROM DUAL)
    SELECT uuid, uuid
      FROM data

출력:

UUID                                      UUID_1
F8FCA4B4D8982B55E0440000BEA88F11      F8FCA4B4D8992B55E0440000BEA88F11

대조적으로 DBMS_RANDOM 결과는 동일합니다.

SQL:

WITH data AS (SELECT DBMS_RANDOM.RANDOM() rand FROM DUAL)
SELECT rand, rand
  FROM data

출력:

RAND    RAND_1
92518726    92518726

더욱 흥미로운 것은 DBMS_RANDOM.RANDOM.RANDOM:

WITH data AS (
        SELECT SYS_GUID () uuid, 
        DBMS_RANDOM.random () rand 
        FROM DUAL)
SELECT uuid a,
       uuid b,
       rand c,
       rand d
  FROM data

SYS_GUID를 안정화하는 SQL Fiddle: http://sqlfiddle.com/ #!4/d41d8/29409

이상한 SYS_GUID 동작을 보여주는 SQL Fiddle: http://sqlfiddle.com/ #!4/d41d8/29411

문서는 불일치(내 항목 강조)를 볼 수 있는 이유를 제공합니다.

주의:

SQL은 명령형(또는 절차형) 언어가 아닌 선언형 언어이기 때문에 명령형 언어인 PL/SQL로 작성된 경우에도 SQL 문에 의해 호출된 함수가 실행되는 횟수를 알 수 없습니다.응용 프로그램에서 특정 횟수만큼 함수를 실행해야 하는 경우 SQL 문에서 해당 함수를 호출하지 마십시오.대신 커서를 사용합니다.

예를 들어, 프로그램에서 선택한 각 행에 대해 함수를 호출해야 하는 경우 커서를 열고 커서에서 행을 선택한 다음 각 행에 대한 함수를 호출합니다.이 기법은 함수에 대한 호출 수가 커서에서 가져온 행 수임을 보장합니다.

기본적으로 Oracle은 sql 문 안에서 함수가 호출되는 횟수를 지정하지 않습니다. 릴리스, 환경, 액세스 경로 등에 따라 다를 수 있습니다.

그러나 중첩된 하위 쿼리의 중첩 해제 장에서 설명한 대로 쿼리 다시 쓰기를 제한하는 방법이 있습니다.

하위 쿼리는 하위 쿼리 본문을 포함하는 문 본문에 병합하여 최적화 도구가 액세스 경로 및 조인을 평가할 때 함께 고려할 수 있도록 합니다.최적화 도구는 일부 예외를 제외하고 대부분의 하위 쿼리를 중첩 해제할 수 있습니다.이러한 예외에는 ROWNUM 유사 열, 집합 연산자 중 하나, 중첩 집계 함수 또는 하위 쿼리의 직접 외부 쿼리 블록이 아닌 쿼리 블록에 대한 상관 참조가 포함되는 계층적 하위 쿼리와 하위 쿼리가 포함됩니다.

위에서 설명한 대로 유사 열을 사용하여 Oracle이 하위 쿼리를 제거하지 못하도록 할 수 있습니다.

SQL> WITH data AS (SELECT SYS_GUID() uuid FROM DUAL WHERE ROWNUM >= 1)
  2  SELECT uuid, uuid FROM data;

UUID                             UUID
-------------------------------- --------------------------------
1ADF387E847F472494A869B033C2661A 1ADF387E847F472494A869B033C2661A

NO_MERGE 힌트는 이를 "수정"합니다.오라클이 인라인 보기를 다시 쓰지 못하도록 합니다.

WITH data AS (SELECT /*+ NO_MERGE */
                    SYS_GUID () uuid FROM DUAL)
SELECT uuid, uuid
  FROM data

문서에서:

NO_MERGE 힌트는 옵티마이저에게 외부 쿼리와 인라인 뷰 쿼리를 단일 쿼리로 결합하지 않도록 지시합니다.이 힌트를 사용하면 보기에 액세스하는 방식에 더 많은 영향을 줄 수 있습니다.

NO_MERGE 힌트가 적용된 SQL Fiddle:

다음과 같은 방식으로 쿼리를 다시 작성하는 방법을 이해하기 위해 여전히 노력하고 있습니다.sys_guid()두 번 호출됩니다.아마도 그것은 버그일 것입니다; 하지만 저는 그것이 제 생각/코드상 버그라고 생각하는 경향이 있습니다.

매우 흥미롭습니다.

구체화 힌트를 사용하여 수정할 수 있습니다.

WITH data AS (SELECT /*+materialize*/SYS_GUID () uuid FROM DUAL)
    SELECT uuid, uuid
      FROM data;

1   F9440E2613761EC8E0431206460A934C    F9440E2613761EC8E0431206460A934C

제 입장에서는 힌트를 추가하는 것만으로 쿼리 결과를 변경할 수 있다면 오라클 버그가 있습니다.메탈링크에 확인을 요청해야 할 수도 있습니다.

언급URL : https://stackoverflow.com/questions/23572605/oracle-sql-understanding-the-behavior-of-sys-guid-when-present-in-an-inline-v