
대용량 데이터를 다른 DBMS로 이관하는 작업은 단순한 insert 반복이 아니다.
특히 MySQL에서 Oracle로 수백만 건의 데이터를 이관하면서, 성능, 데이터 정합성, 중복 처리, 재처리 가능성까지 고려해야 한다.
이 글은 실무에서 경험한 Python 기반 병렬 이관 전략을 공유한다.
pymysql: MySQL 데이터 조회용cx_Oracle: Oracle 데이터 입력용concurrent.futures: 병렬 처리logging: 로깅 및 예외 추적전체 ID 범위를 균등하게 나눈 후 Thread 단위로 병렬 처리했다.
예:
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
import pymysql
import cx_Oracle
from concurrent.futures import ThreadPoolExecutor
import logging
# 설정 정보
mysql_config = {...}
oracle_config = {...}
logging.basicConfig(level=logging.INFO)
def fetch_data(start_id, end_id):
with pymysql.connect(**mysql_config) as conn:
with conn.cursor() as cur:
cur.execute("""
SELECT USER_CODE, TOKEN, APP_ID, OS_TYPE, CREATED_AT
FROM source_table
WHERE ID BETWEEN %s AND %s
""", (start_id, end_id))
return cur.fetchall()
def insert_data_to_oracle(data):
with cx_Oracle.connect(**oracle_config) as conn:
with conn.cursor() as cur:
for row in data:
try:
cur.execute("""
INSERT INTO target_table (
USER_CODE, TOKEN, APP_ID, OS_TYPE, CREATED_AT
) VALUES (
:1, :2, :3, :4, TO_TIMESTAMP(:5, 'YYYY-MM-DD HH24:MI:SS.FF')
)
""", row)
except cx_Oracle.IntegrityError as e:
if 'ORA-00001' in str(e):
logging.debug("중복 건 무시: %s", row)
continue
else:
raise
conn.commit()
def migrate_range(start_id, end_id):
logging.info("Start range: %s - %s", start_id, end_id)
data = fetch_data(start_id, end_id)
logging.info("Fetched %d rows", len(data))
insert_data_to_oracle(data)
logging.info("Finished range: %s - %s", start_id, end_id)
# 병렬 처리 실행
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)
INFO Start range: 1 - 1000000
INFO Fetched 999992 rows
INFO Finished range: 1 - 1000000
Python 기반의 병렬 이관은 구현이 단순하면서도 유연하게 확장 가능하다.
특히 Oracle의 제약조건을 고려한 예외 중심 설계, 구간 분할 전략, 로깅 기반 추적은
실무에서 대용량 데이터를 안정적으로 처리하는 데 큰 도움이 되었다.
요약 글은 티스토리 MySQL에서 Oracle로, 대용량 데이터를 안전하게 이관한 방법 (Python 사용기) 에서 확인할 수 있다.