모든 행 업데이트


12

단일 열에 대해 매우 큰 Oracle 테이블의 모든 행을 업데이트하는 가장 효율적인 방법을 알고 싶습니다. 예를 들면 다음과 같습니다.

update mytable set mycolumn=null;

또는:

update mytable set mycolumn=42;

내 지식이 매우 부실 할 수 있습니다. 내가하는 일은 테이블을 변경하여 열을 삭제하는 것입니다. 그런 다음 테이블을 변경하여 사용하려는 새 값의 기본값으로 열을 추가합니다. 그런 다음 테이블을 변경하여 열의 기본값을 제거합니다. 업데이트를 실행하는 것보다 훨씬 빠르지 만 더 나은 방법이 있다고 생각합니다.


내가 이해하는 한 기본값이있는 새로운 null이 아닌 열을 추가하는 것은 Oracle에서 메타 데이터 만 변경됩니다. "모든 행을 동일한 값으로 업데이트"사례를 최적화했는지 의심합니다. 이것이 일반적인 작업입니까?
Martin Smith

1
두 가지 방법을 모두 시도하고 시간을 정하십시오. 이 일을 방해하는 이유는 무엇입니까? 다른 결과가 아니라 동일한 결과로 끝나야한다는 사실을 보라! 그렇지 않으면 비교가 유효하지 않습니다.
tvCa

@tvCa 나는 두 가지 방법을 모두 시도했다. 방금 업데이트를 수행하면 약 2 시간 동안 실행 된 다음 종료합니다. 열을 삭제하면 몇 초 밖에 걸리지 않습니다. 기본값이없는 열을 추가하는 경우 (열이 널임) 몇 초 밖에 걸리지 않습니다. 기본값으로 열을 추가하는 데 약 30 분이 걸립니다. 예를 들어 열의 모든 값을 '일부 값'으로 설정하려면 현재 열을 삭제하고 추가하십시오. 더 빠른 방법이 있는지 알고 싶습니다.
kainaw

2
11gR2를 사용하고 있습니까? @MartinSmith가 맞습니다. DEFAULT를 NOT NULL로 사용하여 새 열을 추가하는 것이 NULL로 추가하는 것보다 훨씬 빠르게 변경되는 방법에 대한 설명 은 여기참조하십시오 (UPDATE 문을 발행하는 것처럼) 테이블의 모든 행을 강제로 업데이트합니다. 내가 본 문제는 DEFAULT 값을 사전에 저장하여 성능이 향상되어 나중에 DEFAULT 값을 제거하는 것입니다. 이 시점에서 NOT NULL 제약 조건도 처리해야합니다.
ansible

답변:


2

이 대량 업데이트를 수행하는 동안이 테이블에 대해 진행중인 다른 활동에 따라 달라집니다. 당신이하고 싶은 일의 샘플을 실행하고 어떤 방법이 가장 좋은지 알 수있는 일종의 테스트 환경이 있기를 바랍니다. 나는 시도 할 것이다 :

  1. 싱글을 실행 update table set column_name = blah;
  2. plSql 루프를 생성하여 테이블의 모든 기본 키를 선택하고 반복 updating the column=blah하고 모든 X 업데이트를 커밋합니다 (10000 일 수 있음). 이 코드를 복사하여 기본 키의 별도 섹션으로 복사하여이 코드를 병렬화 할 수 있습니다.

우리는 OLTP 시스템에서 매우 적극적으로 사용되는 테이블과 비슷한 문제를 겪었고이를 5 배 병렬화 할 수 있었고 10000마다 커밋하는 100+ MM 행 테이블에 대한 사용자 잠금 영향없이 실행할 수있었습니다. 테이블이 크거나 실행중인 응용 프로그램의 종류가 크지 만 이러한 종류의 솔루션이 적합 할 수 있습니다.


0

빠른 속도 UPDATE를 위해서는 발사중인 트리거가 없는지 확인하십시오.

SELECT trigger_name, status FROM user_triggers WHERE table_name = 'MYTABLE';

ALTER TABLE mytable DISABLE ALL TRIGGERS;

완료되면 원하는 것을 다시 활성화하십시오.

ALTER TRIGGER mytrigger ENABLE;

인덱스 유지 관리 오버 헤드가 발생할 수도 있습니다. 인덱스를 별도로 다시 작성하십시오. 그렇게하려면 pappes의 대답이 도움이되어야합니다 : https : //.com/questions/129046/disable-and-later-enable-all-table-indexes-in-oracle

나는 여기에 참고로 pappes의 대답을 반복하고 있습니다. (이 SPOOL 명령은 플랫폼 및 환경에 대한 가정을합니다.)

set pagesize 0    
alter session set skip_unusable_indexes = true;
spool c:\temp\disable_indexes.sql
select 'alter index ' || u.index_name || ' unusable;' from user_indexes u;
spool off
@c:\temp\disable_indexes.sql

가져 오기 ...

select 'alter index ' || u.index_name || ' rebuild online;'
  from user_indexes u;

-1

색인을 제거하십시오. 열을 업데이트하십시오. 인덱스를 다시 돌려줍니다. 그러나 열에 모든 행에 대해 하나의 동일한 값이 포함되어 있으면 인덱스를 삭제할 수 있습니다.


-2

공간 제한이없는 경우 해당 테이블에 새 열이 추가 된 테이블과 동일한 새 테이블을 만들고 이전 테이블을 삭제할 수 있습니다.

create new_table as
select old_table.*, (with or without default_Value) as new_column
from old_table;

1
이것이 더 효율적입니까? 왜? 기존 테이블을 참조하는 FK가있는 경우 어떻게해야합니까?
ypercubeᵀᴹ

예, 다른 샘플 테이블에서 시도하여 결과를 직접 볼 수 있습니다. FK가 있으면 정확히 알지 못하지만 효율적인 경우 비활성화하고 활성화 할 수 있습니다.
E_Salamon 2016 년

-3

여러 업데이트 / 커밋 시퀀스를 시도하십시오. 커밋없이 너무 많은 행을 삽입 / 업데이트 / 삭제하면 많은 IO로드가 발생합니다. 블록 크기와 레코드 크기 및 내용을 알고 있으면 상당히 최적화 할 수 있습니다.

테이블에서 전체 데이터를 삭제하려면 truncate table x보다 낫습니다 delete from x. 또한 제거는 또 다른 프로세스 워크로드를 만듭니다.

편집 :inmemory 옵션 을 사용 하여 메모리에 테이블을 열 형식으로로드 한 다음 업데이트를 수행 할 수 있습니다. 그것은 실제로 DB의 관계와 구조에 달려 있습니다. 이 기사를 참조하십시오 .


3
테이블의 한 열을 업데이트하려고합니다. 나는 표시되지 않습니다 truncate또는 delete어떤 도움이 될 것입니다.
ypercubeᵀᴹ

@ypercube 방금 커밋없이 여러 데이터 조작으로 원치 않는 IO로드를 얻는 방법을 설명했습니다. 업데이트 또는 다른 OLTP 중 하나입니다.
교활한

3
커밋이 얼마나 자주 I / O를 줄이는 지 설명해 주 시겠습니까? 체크 포인트로 인해 I / O가 증가 하지 않습니까?
mustaccio

3
비 전통적인 용어 ( "tx journal", "세션 변경")를 사용하는 것은 약간 혼란 스럽습니다. 여러 개의 짧은 트랜잭션을 사용하든 하나의 대규모 트랜잭션을 사용하든 생성 된 리두 레코드의 총량은 동일합니다. I / O 작업은 커밋시 또는 리두 버퍼가 거의 가득 찼을 때 발생하는 리두 로그 버퍼가 디스크에 기록 될 때만 발생합니다 (지금은 버퍼 캐시 체크 포인트 만 남김). 결과적으로 자주 커밋하면 추가 I / O가 발생하므로 어떻게 I / O를 줄일 수 있는지 궁금합니다 .
mustaccio

4
당신은 톰 카이트는 "자주 커밋"에 대해 무슨 얘기 읽어보십시오 : asktom.oracle.com/pls/apex/... " 잘못, 잘못, 잘못 .... 그래서 잘못 그래서 아주 아주 잘못된. "
a_horse_with_no_name
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.