2012-03-20 4 views
0

oracle 9i에서 작업 중입니다. 나는 135,000,000 개의 레코드를 가진 테이블을 가지고 있는데, 각각의 파티션은 약 1 개의 파티션을 가지고있다. 10,000,000 개의 행 모든 색인 및 모든.오라클에 많은 수의 데이터가 포함 된 쿼리 삭제

새로운 비즈니스 요구 사항으로 약 70,000,000 개의 행을 삭제해야합니다.

그래서 별도의 테이블로 삭제할 행의 백업을 만들었습니다.

Table1 <col1, col2........> -- main table (135,000,000 rows) 

Table2 <col1, col2........> -- backup table (70,000,000 rows) 

다음 쿼리를 삭제하려고 시도했습니다.

Delete from table1 t1 where exists (select 1 from table2 t2 where t2.col1 = t1.col1) 

그러나 무한한 시간이 걸립니다.

는도 여전히 이상 12 시간 운영하고
declare 
cursor c1 is 
select col1 from table2; 
c2 c1%rowtype; 
cnt number; 
begin 
cnt :=0; 
open c1; 
loop 
    fetch c1 into c2; 
    exit when c1%notfound; 

    delete from table1 t1 where t1.col1 = c2.col1; 
    if cnt >= 100000 then 
     commit; 
    end if; 
    cnt:=cnt+1; 
end loop; 
close c1; 
end; 

을 시도했다. 아직 완료되지 않았습니다.

table1에는 여러 개의 인덱스가 있고 table2에는 col1의 인덱스가 있습니다. 모든 테이블과 인덱스가 분석됩니다.

이 시나리오를 위해 최적화 할 방법이 있는지 알려주십시오.

감사합니다.

+0

코드가 실제로 그렇게 보이면 행 100000 이후의 모든 행을 커밋합니다. 이는 원하는 것이 아니며 느리게 진행될 것입니다. 커밋 후 cnt : = 0을 설정하십시오. –

+0

예 카운터 재설정이 필요합니다. 오타가 남아 있다고 생각합니다. 하지만 색인을 삭제하고 최상위 답변으로 다시 만드는 것이 더 좋았습니다. –

답변

4

드롭 모든 인덱스 (백업이이 문을 생성) 사용 그것에서 생성, 백업 테이블을 작성하는 데 사용되는 select 문 삭제 명령 재 작성 모든 인덱스

4

앞서이 문제를 직면하고 기억한다. 유지하려는 레코드를 (

1) 동일한 구조

이 또 다른 테이블을 작성) 새로운 테이블에 삽입 : 그것은 다른 삭제 작업을보다 빠르게 밖으로 일하기 때문에이 경우, 우리는이 일에 의지))

3이 속도를 이전 테이블

4) 이름 바꾸기에게 나는 이것이이 백업에 대해 필터링 저렴 가정에 대답하는거야

0

새로운 테이블을 삭제하는 직접 경로 삽입을 사용하여 테이블,하지만 그것 w 아마도 백업 테이블을 채우는 데 사용한 기준의 부정을 사용하는 것이 더 저렴할 것입니다.

1) 동일한 구조의 새 테이블을 만듭니다. 인덱스, 제약 조건 또는 트리거가 없습니다.

필요한 이것은 대량의 피할 경우

2)

 
    select 'insert /*+ append nologging */ into new_table partition (' || n.partition_name || ') select * from old_table partition (' || o.partition_name || ') minus select * from bak_table partition (' || b.partition_name || ');' 
    from all_tab_partitions o, all_tab_partitions n, all_tab_partitions b 
    where o.partition_no = all(n.partition_no, b.partition_no) 
     and o.table_name = 'OLD_TABLE' and o.table_owner = 'OWNER' 
     and n.table_name = 'NEW_TABLE' and n.table_owner = 'OWNER' 
     and b.table_name = 'BAK_TABLE' and b.table_owner = 'OWNER'; 
    -- note, I haven't run this it may need minor corrections in addition to the obvious substitutions 

3) 이전 쿼리

4) 인덱스, 제약 조건을 구축의 결과를 확인하고 실행 및 트리거 재실행 및 실행 취소는 삭제와 비교됩니다.직접 경로에 대한 APPEND 힌트가 더 리두를 줄이기 위해 로깅을 삽입하지 않습니다 - 백업해야 나중에 는

당신은 아마 병렬로 더 빨리 갈 수 적은 패스에 정렬 할 수 있습니다 덩어리로 작업을 중단하기 위해 파티션을 활용 삽입 + 병렬 선택,하지만 아마 필요하지 않습니다. 삽입하지 않고 병렬 선택을 수행하지 말고 "세션 변경 병렬 dml 사용"

+0

'nologging'은 실제 힌트가 아니므로'append' 만 필요합니다. –

1

테이블이 분할되었다고 말합니다. 특정 파티션의 모든 데이터를 삭제하겠습니까? 그렇다면 삭제할 7 천만 개의 행이있는 7 개의 파티션을 간단히 삭제할 수 있어야합니다. 그러나 나는 당신의 문제가 그렇게 간단하지 않다고 가정하고 있습니다.

당신이 중간 커밋을 할 수 있다면, 그건 당신이 트랜잭션 일관성에 대해 걱정하지 않는 것을 의미한다, 가장 효율적인 방법이 없다면

CREATE TABLE rows_to_save 
    AS SELECT * 
     FROM table1 
     WHERE <<criteria to select the 65 million rows you want to keep>> 

TRUNCATE TABLE table1; 

INSERT /*+ append */ 
    INTO table1 
SELECT * 
    FROM rows_to_save; 

의 라인을 따라 가능성이 뭔가, 즉 아니라 백업 테이블을 만드는 것보다 , 단순히 당신은 또한 떨어 뜨리거나 DELETE를 실행하기 전에 인덱스와 제약 조건을 비활성화 혜택을 누릴 수있는 DELETE

DELETE FROM table1 
WHERE <<criteria to select the 70 million rows you want to keep>> 

를 발행하는 것이 더 효율적이 될 것입니다.

관련 문제