268 lines
7.0 KiB
Markdown
268 lines
7.0 KiB
Markdown
|
|
# 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 의존성 설치**
|
||
|
|
```bash
|
||
|
|
pip install pymysql pandas tqdm sqlalchemy
|
||
|
|
```
|
||
|
|
|
||
|
|
## 사용 방법
|
||
|
|
|
||
|
|
### 1. 전체 데이터 마이그레이션
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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. 테스트 마이그레이션 (일부 데이터만)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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 환경에서 실행
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 백엔드 컨테이너에 접속
|
||
|
|
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]
|
||
|
|
...
|
||
|
|
```
|
||
|
|
|
||
|
|
## 데이터 검증
|
||
|
|
|
||
|
|
마이그레이션 후 데이터 검증:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 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 데이터)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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 내보내기
|
||
|
|
|
||
|
|
```sql
|
||
|
|
SELECT * FROM kor_price
|
||
|
|
INTO OUTFILE '/tmp/kor_price.csv'
|
||
|
|
FIELDS TERMINATED BY ','
|
||
|
|
ENCLOSED BY '"'
|
||
|
|
LINES TERMINATED BY '\n';
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. PostgreSQL로 가져오기
|
||
|
|
|
||
|
|
```sql
|
||
|
|
COPY price_data(ticker, timestamp, open, high, low, close, volume)
|
||
|
|
FROM '/tmp/kor_price.csv'
|
||
|
|
DELIMITER ','
|
||
|
|
CSV HEADER;
|
||
|
|
```
|
||
|
|
|
||
|
|
이 방법이 Python 스크립트보다 10-100배 빠를 수 있습니다.
|