penti/scripts/MIGRATION_GUIDE.md

7.0 KiB

MySQL to PostgreSQL 데이터 마이그레이션 가이드

개요

make-quant-py에서 사용하던 MySQL 데이터베이스의 데이터를 새로운 PostgreSQL 데이터베이스로 마이그레이션하는 스크립트입니다.

마이그레이션 대상

MySQL 테이블 PostgreSQL 테이블 설명
kor_ticker assets 종목 정보
kor_price price_data 주가 데이터 (시계열)
kor_fs financial_statements 재무제표

사전 요구사항

  1. MySQL 데이터베이스 접근 가능

    • 호스트, 사용자, 비밀번호, 데이터베이스명 확인
  2. PostgreSQL 데이터베이스 준비 완료

    • Docker Compose로 실행 중
    • Alembic 마이그레이션 완료
  3. Python 의존성 설치

    pip install pymysql pandas tqdm sqlalchemy
    

사용 방법

1. 전체 데이터 마이그레이션

cd pension-quant-platform

python scripts/migrate_mysql_to_postgres.py \
  --mysql-host localhost \
  --mysql-user your_user \
  --mysql-password your_password \
  --mysql-database quant_db

2. 테스트 마이그레이션 (일부 데이터만)

python scripts/migrate_mysql_to_postgres.py \
  --mysql-host localhost \
  --mysql-user your_user \
  --mysql-password your_password \
  --mysql-database quant_db \
  --price-limit 10000 \
  --fs-limit 10000
  • --price-limit: 주가 데이터 제한 (10,000개만)
  • --fs-limit: 재무제표 데이터 제한 (10,000개만)

3. Docker 환경에서 실행

# 백엔드 컨테이너에 접속
docker-compose exec backend bash

# 마이그레이션 실행
python /app/scripts/migrate_mysql_to_postgres.py \
  --mysql-host host.docker.internal \
  --mysql-user root \
  --mysql-password password \
  --mysql-database quant_db

주의: Docker에서 호스트의 MySQL에 접근하려면 host.docker.internal 사용

마이그레이션 프로세스

1. 종목 데이터 (kor_ticker → assets)

  • 전체 종목 조회
  • UPSERT 방식으로 저장 (기존 데이터 업데이트)
  • 100개 단위로 커밋

소요 시간: 약 1-2분

2. 주가 데이터 (kor_price → price_data)

  • 배치 처리 (10,000개 단위)
  • UPSERT 방식
  • 1,000개 단위로 커밋

소요 시간: 데이터 양에 따라 다름

  • 100만 레코드: 약 10-15분
  • 1,000만 레코드: 약 1-2시간

3. 재무제표 데이터 (kor_fs → financial_statements)

  • 배치 처리 (10,000개 단위)
  • UPSERT 방식
  • 1,000개 단위로 커밋

소요 시간: 데이터 양에 따라 다름

  • 100만 레코드: 약 10-15분
  • 1,000만 레코드: 약 1-2시간

예상 소요 시간 (전체)

데이터 규모 소요 시간
소규모 (10만 레코드) 5-10분
중규모 (100만 레코드) 30분-1시간
대규모 (1,000만+ 레코드) 2-4시간

진행 상황 모니터링

스크립트는 tqdm 프로그레스 바를 사용하여 진행 상황을 표시합니다:

=== 종목 데이터 마이그레이션 시작 ===
MySQL에서 2,500개 종목 데이터 읽기 완료
종목 데이터 저장: 100%|████████████| 2500/2500 [00:15<00:00, 165.43it/s]
종목 데이터 마이그레이션 완료: 2,500개

=== 주가 데이터 마이그레이션 시작 ===
전체 주가 레코드 수: 5,000,000개
배치 1: 10,000개 레코드 처리 중...
주가 데이터 저장: 100%|████████████| 10000/10000 [01:23<00:00, 120.15it/s]
...

데이터 검증

마이그레이션 후 데이터 검증:

# PostgreSQL 레코드 수 확인
curl http://localhost:8000/api/v1/data/stats

# 응답 예시:
{
  "assets": {
    "total": 2500,
    "active": 2500
  },
  "price_data": {
    "total_records": 5000000
  },
  "financial_statements": {
    "total_records": 3000000
  }
}

문제 해결

1. 연결 오류

오류: pymysql.err.OperationalError: (2003, "Can't connect to MySQL server")

해결:

  • MySQL 서버가 실행 중인지 확인
  • 호스트, 포트 정보 확인
  • 방화벽 설정 확인

2. 메모리 부족

오류: MemoryError

해결:

  • --price-limit, --fs-limit 옵션 사용
  • 배치 크기 조정 (스크립트 내 batch_size 변수)

3. 중복 키 오류

오류: IntegrityError: duplicate key value

해결:

  • UPSERT 로직이 자동으로 처리
  • 이미 마이그레이션된 데이터는 업데이트됨

4. 느린 속도

해결:

  • PostgreSQL 인덱스 임시 비활성화
  • maintenance_work_mem 증가
  • 병렬 처리 고려

재실행

마이그레이션은 UPSERT 방식이므로 여러 번 실행 가능합니다:

  • 기존 데이터: 업데이트
  • 신규 데이터: 삽입

중단된 경우 다시 실행하면 이어서 진행됩니다.

주의사항

  1. 백업: MySQL 데이터베이스 백업 권장
  2. 디스크 공간: PostgreSQL에 충분한 공간 확보
  3. 네트워크: 안정적인 연결 필요
  4. 타임아웃: 대용량 데이터는 타임아웃 설정 조정

예시

실제 사용 예시 (make-quant-py 데이터)

python scripts/migrate_mysql_to_postgres.py \
  --mysql-host localhost \
  --mysql-user root \
  --mysql-password mypassword \
  --mysql-database quant

# 출력:
============================================================
MySQL → PostgreSQL 데이터 마이그레이션 시작
시작 시간: 2025-01-29 15:30:00
============================================================

=== 종목 데이터 마이그레이션 시작 ===
MySQL에서 2,547개 종목 데이터 읽기 완료
종목 데이터 저장: 100%|████████| 2547/2547 [00:18<00:00]
종목 데이터 마이그레이션 완료: 2,547개

=== 주가 데이터 마이그레이션 시작 ===
전체 주가 레코드 수: 4,832,156개
배치 1: 10,000개 레코드 처리 중...
주가 데이터 저장: 100%|████████| 10000/10000 [01:25<00:00]
...
주가 데이터 마이그레이션 완료: 4,832,156개

=== 재무제표 데이터 마이그레이션 시작 ===
전체 재무제표 레코드 수: 2,145,789개
배치 1: 10,000개 레코드 처리 중...
재무제표 데이터 저장: 100%|████████| 10000/10000 [01:30<00:00]
...
재무제표 데이터 마이그레이션 완료: 2,145,789개

============================================================
마이그레이션 완료!
종료 시간: 2025-01-29 17:45:00
소요 시간: 2:15:00
============================================================

대안: CSV 내보내기/가져오기 (빠른 방법)

대용량 데이터의 경우 CSV를 통한 마이그레이션이 더 빠를 수 있습니다:

1. MySQL에서 CSV 내보내기

SELECT * FROM kor_price
INTO OUTFILE '/tmp/kor_price.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';

2. PostgreSQL로 가져오기

COPY price_data(ticker, timestamp, open, high, low, close, volume)
FROM '/tmp/kor_price.csv'
DELIMITER ','
CSV HEADER;

이 방법이 Python 스크립트보다 10-100배 빠를 수 있습니다.