대용량 E-Commerce 데이터를 파이썬으로 자동 생성하여 오라클 데이터베이스에 초고속으로 적재(SQL*Loader)하는 시스템을 구축하면서 마주쳤던 6가지 핵심 오류와 그 해결 과정을 상세히 기록합니다.
- 상황: 수십만 건의 데이터를 메모리에 배열(List) 형태로 들고 있다가 한 번에 SQL 구문으로 출력(
03_seed_data.sql)하려다 보니 파이썬 프로세스에서 메모리 초과(OOM)가 발생할 위험이 컸습니다. - 해결: 파이썬의
yield키워드를 사용한 제너레이터(Generator) 패턴과csv.DictWriter를 결합하여 데이터를 한 줄씩(Streaming) 즉시 파일로 써내려가는 방식으로 아키텍처를 전면 개편했습니다. 그 결과 메모리 사용량을 O(1) 수준으로 극적으로 낮출 수 있었습니다.
- 상황: 생성된 25만 건 이상의
.sql스크립트를 SQL*Plus로 한 줄씩INSERT하려니 수 시간이 소요될 정도로 적재 속도가 너무 느렸습니다. - 해결: 오라클에서 대용량 데이터를 적재할 때 사용하는 SQL*Loader (
sqlldr) 툴을 활용하기로 결정했습니다. 파이썬 스크립트가 순수 데이터인.csv파일과 제어 파일인.ctl을 자동 생성하도록OracleExporter를 개편하였고, 적재 속도를 단 몇 초 단위로 단축했습니다.
- 에러 메시지:
ORA-01918: user 'ECOMMERCE' does not exist - 상황: 오라클 23ai Free 버전을 도커 컨테이너로 띄우고
sqlplus로 접속하여 설치 스크립트(install.sql,uninstall.sql)를 실행했으나, 스키마 유저를 찾을 수 없거나 생성할 수 없는 문제가 발생했습니다. - 원인: 최신 오라클 데이터베이스는 멀티테넌트(CDB/PDB) 아키텍처를 따릅니다. 기본 접속 시
CDB$ROOT컨테이너에 접속되는데, 이 루트 영역에서는 일반 서비스 유저(ECOMMERCE)를 관리할 수 없습니다. - 해결: 모든 DDL 스크립트(
install.sql,uninstall.sql) 최상단에ALTER SESSION SET CONTAINER = FREEPDB1;구문을 삽입하여, 플러거블 데이터베이스(PDB)로 세션이 이동한 뒤 유저 관리와 테이블 생성을 수행하도록 수정했습니다.
- 에러 메시지:
SQL*Loader-522: lfiopn failed for file (data/categories.log) - 상황: 파이썬으로 로컬(Mac/Windows)에서 생성한 결과물(
output/) 폴더를docker cp명령어를 이용해 오라클 도커 컨테이너 내부로 복사한 뒤,load_data.sh를 실행했으나 위 오류가 발생하며 적재가 실패했습니다. - 원인:
docker cp를 통해 호스트에서 도커 내부로 복사된 파일들은 소유자가root로 지정됩니다. 하지만 SQL*Loader는oracle계정 권한으로 실행되므로,root소유의 폴더에 로그 파일(.log)이나 배드 파일(.bad)을 작성할 권한이 없어서 발생한 에러입니다. - 해결:
docker cp후 반드시 도커 내부의 파일 소유권을oracle:oinstall로 변경해주는 절차를 필수화했습니다.docker exec -u 0 oracle26ai chown -R oracle:oinstall /home/oracle/all_schema
- 에러 메시지:
ORA-01722: unable to convert string value containing 'D' to a number - 상황: 윈도우 환경이나 특정 파이썬 설정에서 CSV 파일을 생성하면, 숫자가 들어가야 할 마지막 컬럼에서 지속적으로 문자열 변환 에러가 발생했습니다.
- 원인: 파이썬 내장
csv모듈은 기본적으로 윈도우 스타일의 줄바꿈인\r\n(캐리지 리턴 + 라인 피드)을 사용합니다. 리눅스 환경의 도커 안에서 SQL*Loader가 이를 파싱할 때, 보이지 않는\r문자가 마지막 숫자 컬럼에 포함되어 "숫자가 아닌 문자가 섞였다"고 판단한 것입니다. - 해결: 파이썬
OracleExporter의csv.DictWriter인스턴스 생성 시lineterminator='\n'옵션을 명시적으로 지정하여, 모든 운영체제에서 리눅스 호환LF포맷으로 파일이 생성되도록 원천 봉쇄했습니다.
- 상황: 마지막 14개 분석/참여 테이블 데이터를 생성한 후
CARTS,REVIEWS,POINT_TRANSACTIONS등의 테이블에서 0건이 적재되거나 이상한 에러가 발생했습니다. - 원인 1 (컬럼 순서 불일치): 파이썬
Faker제너레이터가yield하는 딕셔너리(Dictionary)의 키 순서와 오라클 테이블의 실제 컬럼 정의(schema_definition.py) 순서가 달랐습니다.csv.DictWriter는 딕셔너리의 키 순서대로 CSV를 생성하지만, SQL*Loader(.ctl)는 오라클 테이블 컬럼 순서대로 데이터를 읽어 들이려다 보니, 문자열("ACTIVE")을 날짜 컬럼(CREATED_AT)에 넣으려다ORA-01841에러가 났습니다. - 원인 2 (데이터 내 줄바꿈 포함):
REVIEWS나COMPLAINTS테이블에Faker.text()로 본문을 넣었는데, 본문 안에 개행 문자(\n)가 포함되어 있었습니다. 기본 SQL*Loader 설정에서는 개행 문자를 새로운 레코드(행)의 시작으로 간주하기 때문에 큰따옴표로 감싸여 있어도 파싱이 깨졌습니다. - 해결:
massive_generator.py의 모든 제너레이터 딕셔너리 반환 순서를schema_definition.py의 컬럼 선언 순서와 단 1개의 오차도 없이 100% 동일하게 일치시켰습니다. (예:point_transactions의tx_type등 변수명도 정확히 일치시킴).Faker.text().replace('\n', ' ')를 사용하여 텍스트 데이터 내부의 줄바꿈을 모두 공백으로 치환하여 SQL*Loader가 헷갈리지 않게 방어 로직을 추가했습니다.