7.0 KiB
7.0 KiB
MySQL to PostgreSQL 데이터 마이그레이션 가이드
개요
make-quant-py에서 사용하던 MySQL 데이터베이스의 데이터를 새로운 PostgreSQL 데이터베이스로 마이그레이션하는 스크립트입니다.
마이그레이션 대상
| MySQL 테이블 | PostgreSQL 테이블 | 설명 |
|---|---|---|
kor_ticker |
assets |
종목 정보 |
kor_price |
price_data |
주가 데이터 (시계열) |
kor_fs |
financial_statements |
재무제표 |
사전 요구사항
-
MySQL 데이터베이스 접근 가능
- 호스트, 사용자, 비밀번호, 데이터베이스명 확인
-
PostgreSQL 데이터베이스 준비 완료
- Docker Compose로 실행 중
- Alembic 마이그레이션 완료
-
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 방식이므로 여러 번 실행 가능합니다:
- 기존 데이터: 업데이트
- 신규 데이터: 삽입
중단된 경우 다시 실행하면 이어서 진행됩니다.
주의사항
- 백업: MySQL 데이터베이스 백업 권장
- 디스크 공간: PostgreSQL에 충분한 공간 확보
- 네트워크: 안정적인 연결 필요
- 타임아웃: 대용량 데이터는 타임아웃 설정 조정
예시
실제 사용 예시 (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배 빠를 수 있습니다.