Backend/Data
MySQL에서 Oracle로, 대용량 데이터를 안전하게 이관한 방법 (Python 사용기)
gigyesik
2025. 5. 16. 18:40
반응형
MySQL에서 Oracle로, 대용량 데이터를 안전하게 이관한 방법 (Python 사용기)
대용량 데이터를 MySQL에서 Oracle로 옮겨야 하는 일이 생겼다.
데이터 양은 약 300만 건. 단순히 insert 문을 반복하기엔 너무 방대했고, 실수하면 복구도 어렵다.
이 글은 그때 내가 Python으로 병렬 이관 스크립트를 작성해, 빠르고 안정적으로 이관을 마친 과정을 공유하는 글이다.
이런 상황이었어요
- ✅ 출발지: MySQL
- ✅ 도착지: Oracle
- ✅ 데이터량: 300만 건 이상
- ✅ 문제: 중복 데이터 발생 가능성 + 너무 오래 걸림 + 재처리 불가
어떤 전략으로 해결했을까요?
✔ 1. ID 범위로 데이터를 나눠 병렬 처리
단일 쓰레드로 300만 건을 처리하는 건 너무 느렸다.
그래서 전체 데이터를 ID 기준으로 세 구간으로 나누고, 세 개의 쓰레드로 병렬 실행했다.
쓰레드 | 처리 범위 (예시) |
---|---|
Thread 1 | ID 1 ~ 1,000,000 |
Thread 2 | ID 1,000,001 ~ 2,000,000 |
Thread 3 | ID 2,000,001 ~ 3,000,000 |
이렇게 나누면 특정 구간만 다시 실행하는 것도 가능해서 유지보수도 훨씬 편해진다.
✔ 2. 중복 insert는 '예외로 무시'하는 방식 사용
Oracle은 같은 데이터를 중복으로 넣으려고 하면 ORA-00001 오류가 난다.
처음에는 MERGE 문도 고민했지만, 성능이 좋지 않아서 결국 단순 insert + 중복 예외 무시 전략을 썼다.
try:
cursor.execute("INSERT INTO ... VALUES ...")
except cx_Oracle.IntegrityError as e:
if 'ORA-00001' in str(e):
pass # 이미 있으면 무시
else:
raise
간단하지만, 속도도 빠르고 안정성도 확보할 수 있는 현실적인 방법이었다.
✔ 3. Python으로 만든 이관 스크립트
대략적인 코드 구조는 다음과 같다:
from concurrent.futures import ThreadPoolExecutor
def migrate_range(start_id, end_id):
# MySQL에서 조회 → Oracle에 insert
# insert 시 ORA-00001 예외는 무시 처리
...
ranges = [
(1, 1000000),
(1000001, 2000000),
(2000001, 3000000)
]
with ThreadPoolExecutor(max_workers=3) as executor:
for start_id, end_id in ranges:
executor.submit(migrate_range, start_id, end_id)
- MySQL에는 pymysql 사용
- Oracle에는 cx_Oracle 사용
- 날짜 포맷은 SQL 쿼리 안에서 TO_TIMESTAMP()로 처리
결과는 어땠을까요?
- ⏱ 기존 2분 30초 → 55초로 단축
- ⚠️ 중복 데이터 무시 성공률 100%
- 🔁 부분 실패 시 구간만 재실행 가능
덕분에 운영 중인 데이터를 안정적으로 마이그레이션할 수 있었다.
마무리하며
이번 작업을 하면서 느낀 점은 이거였다:
데이터 이관은 정확도보다도 “복구 가능성”을 설계하는 게 더 중요하다.
혹시 비슷한 이관 작업을 준비 중이라면,
병렬 처리 + 예외 무시 + 구간 분할 전략을 꼭 한 번 고려해보시길 바란다.
더욱 자세한 글은 velog MySQL → Oracle 대용량 데이터 이관 – 병렬 처리와 예외 처리 전략 (Python 기반) 에서 확인할 수 있다.
반응형