대용량 데이터를 마이그레이션하거나 백업 테이블을 생성할 때,

가장 많이 쓰는 SQL 문 중 하나가 바로 INSERT INTO ... SELECT입니다. 📥

하지만 데이터가 수십만~수백만 건에 달하면,
속도가 느려지고 트랜잭션 병목 현상이 생기기 시작하죠.

오늘은 실무에서 자주 쓰이는 INSERT SELECT 성능 최적화 방법
정리해 드릴게요. 속도 차이를 체감할 수 있을 겁니다! ⚡


1️⃣ 기본 구문 복습

INSERT INTO target_table (col1, col2, ...)
SELECT col1, col2, ...
FROM source_table
WHERE 조건;


문법 자체는 간단하지만, 성능은 설계와 환경 설정에 따라 크게 달라집니다.


⚡ 2. INSERT SELECT 속도 향상 팁

✅ (1) Direct-Path Insert 사용

INSERT /*+ APPEND */ INTO target_table
SELECT * FROM source_table;


  • APPEND 힌트를 사용하면 Direct-Path Insert가 실행되어
    버퍼 캐시를 거치지 않고 바로 데이터 파일에 기록됩니다.
  • 단, 이 방법은 로그를 적게 쓰고 빠르지만,
    UNDO 사용이 제한되며 병렬처리나 제약조건 주의가 필요합니다.

📌 주의: Direct-Path는 테이블이 NOLOGGING 또는 LOGGING 조건에 따라
Redo log에 기록되지 않을 수 있으니 복구 계획이 있을 경우 유의하세요.


✅ (2) 병렬 처리(PARALLEL) 힌트 추가

INSERT /*+ APPEND PARALLEL(tgt, 4) */ INTO target_table tgt
SELECT /*+ PARALLEL(src, 4) */ * 
FROM source_table src;
  • PARALLEL(table_alias, degree) 힌트로 동시 처리 스레드 수 지정 가능
  • 소스와 타겟 테이블 모두 병렬 설정 가능
  • 병렬 옵션은 CPU 리소스를 많이 사용하므로 서버 상태를 고려해야 합니다

✅ (3) 제약조건, 인덱스 일시 제거

  • INSERT 대상 테이블에 많은 제약조건(FK, CHECK)이나 인덱스가 있으면 느려집니다
  • 가능하면 아래처럼 처리하세요
-- 인덱스 비활성화
ALTER INDEX index_name UNUSABLE;

-- 제약조건 비활성화
ALTER TABLE table_name DISABLE CONSTRAINT constraint_name;


💡 작업 완료 후에는 반드시 인덱스와 제약조건을 다시 활성화해야 합니다!


✅ (4) 자동 커밋 방지 + 트랜잭션 쪼개기

  • 대용량 INSERT 시 트랜잭션이 커지면 성능이 급격히 저하
  • 가능하면 작게 나눠서 COMMIT을 주기적으로 수행
-- 예: PL/SQL 루프 내 1000건마다 COMMIT
FOR rec IN (
  SELECT * FROM source_table
) LOOP
  INSERT INTO target_table VALUES (rec.col1, rec.col2, ...);
  i := i + 1;
  IF MOD(i, 1000) = 0 THEN
    COMMIT;
  END IF;
END LOOP;
COMMIT;


📊 요약 정리

방법설명
/*+ APPEND */Direct-Path Insert 사용으로 속도 향상
/*+ PARALLEL */병렬 처리로 대용량 데이터 동시 삽입
인덱스/제약 제거INSERT 중 리소스 낭비 줄이기
트랜잭션 분할Out-of-memory 방지 및 속도 개선
UNDO/LOGGING 설정복구 가능성과 성능의 균형 고려 필요

✅ 마무리 요약

대량의 데이터를 빠르게 삽입하려면 단순 INSERT SELECT만으론 부족합니다.
APPEND, PARALLEL 같은 힌트를 활용하고, 제약조건·트랜잭션 구조
현명하게 설계하면 작업 속도를 몇 배 이상 향상시킬 수 있어요! 🚀

단, 성능을 올리는 만큼 데이터 무결성과 복구 전략도 함께 고려하는 게 중요합니다.
빠르게 넣는 것도 좋지만, 안전하게 넣는 방법도 꼭 기억하세요.