오라클 버그?SELECT는 속임수를 반환하지 않으며 SELECT의 INSERT에는 중복 행이 있습니다.

StackOverflow https://stackoverflow.com/questions/1868417

  •  18-09-2019
  •  | 
  •  

문제

작업 중인 Oracle 인스턴스에서 이상한 동작이 발생합니다.이것은 Itanium의 11gR1이며 RAC도 없고 화려하지도 않습니다.궁극적으로 저는 데이터 웨어하우스 시나리오에서 하나의 Oracle 인스턴스에서 다른 인스턴스로 데이터를 이동하고 있습니다.

DB 링크를 통해 실행되는 반복잡한 보기가 있습니다.대형 테이블에서는 내부 조인 4개, 중간 크기 테이블에서는 왼쪽 조인 5개입니다.

문제는 다음과 같습니다.SQL Developer(또는 SQL*Plus)에서 뷰를 테스트하면 아무 중복도 없이 괜찮은 것 같습니다.그러나 실제로 뷰를 사용하여 테이블에 데이터를 삽입하면 많은 수의 속임수가 발생합니다.

편집하다:- 데이터가 빈 테이블로 이동합니다.쿼리의 모든 테이블은 데이터베이스 링크에 있습니다.쿼리에 전달되는 유일한 것은 날짜입니다(예:INSERT INTO 대상 SELECT * FROM 뷰 WHERE view.datecol = dQueryDate) -

뷰에 대한 PK로 분할된 select 문에 ROW_NUMBER() 함수를 추가해 보았습니다.모든 행은 1로 번호가 다시 지정됩니다.그러나 다시 한 번 삽입으로 실행되는 동일한 명령문은 이전과 동일한 속임수를 생성하며 이제는 편리하게 번호가 지정됩니다.속이는 행의 수는 키당 동일하지 않습니다.일부 레코드는 4번 존재하고 일부 레코드는 한 번만 존재합니다.

나는 이것이 매우 당혹스러운 행동이라고 생각합니다.:) SET 테이블(고유 행만)과 MULTISET 테이블(중복 행 허용)이 있지만 Oracle에는 그러한 기능이 없는 Teradata 작업이 생각납니다.

클라이언트에 행을 반환하는 선택은 해당 행을 다른 위치에 삽입하는 선택과 동일하게 작동해야 합니다.이런 일이 발생하는 정당한 이유를 상상할 수는 없지만 어쩌면 상상력의 실패로 고통받고 있는 것일 수도 있습니다.;)

다른 사람도 이런 현상을 경험한 적이 있는지, 아니면 이 플랫폼의 버그인지 궁금합니다.

해결책

@Gary 덕분에 "{query}에 대한 설명 계획"을 사용 하여이 바닥에 도달 할 수있었습니다. "테이블에서 선택 * (dbms_xplan.display);".설명하는 것은 실제로 익숙해진다 INSERT의 경우 SELECT와 매우 다릅니다.

SELECT의 경우 대부분의 계획 작업은 'TABLE ACCESS BY INDEX ROWID' 및 'INDEX UNIQUE SCAN'입니다.'조건자 정보' 블록에는 쿼리의 모든 조인 및 필터가 포함됩니다.마지막에는 이렇게 말합니다 "참고 - 완전 원격 성명".

INSERT의 경우 인덱스에 대한 참조가 없습니다.'Predicate Information' 블록은 세 줄로 구성되어 있으며 새로운 'Remote SQL' 블록은 다음과 같습니다. 9 작은 SQL 문.

데이터베이스는 내 쿼리를 9개의 하위 쿼리로 분할한 다음 이를 로컬로 조인하려고 시도합니다.더 작은 선택 항목을 실행하여 중복 소스를 찾았습니다.

나는 이것이 원격 링크와 관련된 Oracle 컴파일러의 버그라고 생각합니다. SQL을 다시 작성할 때 논리적 결함이 발생합니다.기본적으로 컴파일러는 WHERE 절을 제대로 적용하지 않습니다.방금 테스트 중이었고 다시 가져오도록 5개의 키가 포함된 IN 목록을 제공했습니다.SELECT는 5개의 행을 다시 가져옵니다.INSERT는 77,000개 이상의 행을 대상에 넣고 IN 목록을 완전히 무시합니다.

{아직도 올바른 동작을 강제하는 방법을 찾고 있습니다. 개발 관점에서는 이상적이지는 않지만 원격 데이터베이스에 뷰를 생성하도록 요청해야 할 수도 있습니다.작업이 완료되면 수정하겠습니다…}

도움이 되었습니까?

해결책

Oracle Bug 인 것 같습니다. 우리는 다음과 같은 작업장을 찾았습니다.insert into select ..."당신처럼 일"select ...", 당신은 select를 서브 선택에 포장 할 수 있습니다.

예를 들어 :

select x,y,z from table1, table2, where ...

-> 복제본이 없습니다

insert into example_table
select x,y,z from table1, table2, where ...

-> 중복 오류

insert into example_table
select * from (
       select x,y,z from table1, table2, where ...
)

-> 복제본이 없습니다

문안 인사

다른 팁

떠오르는 것은 일반적으로 Select를위한 Optimizer 계획이 First_rows 계획을 선호한다는 것입니다. 그러나 삽입물은 삽입물입니다 ... Select는 all_rows 계획을 선호합니다. 전체 데이터 세트. dbms_xplan.display_cursor (v $ sql의 sql_id 사용)를 사용하여 쿼리 계획을 확인합니다.

DB 링크를 통해 반 복잡한보기가 있습니다. 4 개의 큰 테이블 위에 4 개의 내부가 결합되고 5 개의 왼쪽은 중간 크기 테이블 위에 결합됩니다. ... 쿼리의 모든 테이블은 데이터베이스 링크에 있습니다.

다시, 잠재적 인 문제점. SELECT의 모든 테이블이 DB 링크의 다른 쪽 끝에 있으면 전체 쿼리가 원격 데이터베이스로 전송되고 resultSet이 반환됩니다. 삽입을 던지면 로컬 데이터베이스가 쿼리를 담당하고 하위 테이블에서 모든 데이터를 가져올 가능성이 높습니다. 그러나 이는 뷰가 로컬 데이터베이스 또는 원격 데이터베이스에 정의되어 있는지 여부에 따라 다를 수 있습니다. 후자의 경우 로컬 최적화기가 우려되는 한, 원격 객체가 하나만 있고 그로부터 데이터가 가져 오면 원격 데이터베이스가 조인을 수행합니다.

원격 DB로 가서 테이블에 삽입하면 어떻게됩니까?

이는 Oracle이 DB 링크를 통한 조인을 처리할 때 발생하는 버그입니다.INSERT 대 SELECT를 사용하지 않는 더 간단한 상황이 있습니다.원격으로 쿼리를 실행하면 중복된 행이 표시되지만 로컬로 실행하면 중복된 행이 표시되지 않습니다.쿼리 간의 유일한 차이점은 원격 쿼리의 테이블에 "@..."이 추가된다는 것입니다.Oracle SQL Developer 3.0을 사용하여 10.2 데이터베이스에서 9i 데이터베이스를 쿼리하고 있습니다.

이는 총 열이 1000개가 넘는 테이블을 조인하지 못하게 하는 Oracle의 버그보다 훨씬 더 어리석은 일입니다. 이는 ERP 시스템을 쿼리할 때 매우 쉽게 수행할 수 있습니다.그리고 아니요, 오류 메시지는 열이 너무 많은 테이블에 관한 것이 아닙니다.

이는 ANSI 구문을 사용하여 LOB 로케이터가 포함된 테이블을 쿼리하는 것을 금지하는 다른 Oracle 데이터베이스 버그만큼이나 어리석은 일입니다.Oracle 구문만 작동합니다!

나에게 몇 가지 옵션이 발생합니다.

  1. 당신이 보는 속임수는 이미 목적지 테이블에 있었다 ??

  2. SELECT에서 삽입중인 테이블을 참조하면 삽입물이 결합 된 선택과 상호 작용합니다.

    삽입 ... 선택 ...

그런 식으로 (Cartesian Products?)는 복제물을 생성합니다.

나는 도울 수 없지만 아마도 당신은 테이블과 관련된 다른 것의 부작용을 경험하고 있다고 생각합니다. 데이터를 조작 할 수있는 트리거가 있습니까?

원래 테이블에 속이 없다고 어떻게 결정 했습니까?

다른 사람들이 지적했듯이 이것은이 이상한 행동에 대한 단순한 설명 인 것 같습니다.

당신을 확인하십시오 JOIN조심스럽게. 잠재적으로 개별 테이블에는 중복이 없지만 ultpecified 조인 CROSS JOINs는 결과 세트에 다중성으로 인해 복제가 복제되도록하고 삽입되면 대상 테이블의 고유성 제약 조건을 위반합니다.

이 경우 내가하는 일은보기 나 CTE에서 쿼리를 중첩하고 중복을 SELECT:

WITH resultset AS (
    -- blah, blah
)
SELECT a, b, c, COUNT(*)
FROM resultset
GROUP BY a, b, c
HAVING COUNT(*) > 1

실행중인 쿼리에 대한 계획을 세우고 그곳에서 데카르트 가입을 찾고 있습니다. 이것은 복제 된 행을 일으키는 누락 된 조건을 나타낼 수 있습니다.

@Pop이 이미 제안했듯이 삽입물이 실행될 때 SQLPLUS에서 다른 로그인을 사용하는 경우이 동작이 발생할 수 있습니다. (다른 로그인에 동일한 이름의 테이블/보기/동의어가있는 경우)

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