Skip to content

Commit a4ff441

Browse files
f-lab-pizclaude
andcommitted
feat: 데이터 마이그레이션 작성
- NULL 값을 기본값으로 변환하는 데이터 마이그레이션 추가 - op.execute()를 사용한 직접 SQL 실행 예제 - plan.md에 데이터 마이그레이션 작성법 상세 문서화 마이그레이션 내용: - stock이 NULL인 행을 0으로 업데이트 - price가 NULL인 행을 1000.00으로 업데이트 학습 내용: - 스키마 마이그레이션 vs 데이터 마이그레이션 차이 - op.execute()로 복잡한 SQL 실행 가능 - 데이터 마이그레이션은 --autogenerate 없이 수동 작성 - downgrade 작성의 어려움과 백업의 중요성 op.execute() 사용 예시: 1. 직접 SQL 실행 2. 멀티라인 쿼리 3. 여러 SQL 문 순차 실행 4. 조건부 실행 (connection.execute) 주의사항: - 대용량 데이터는 배치 처리 고려 - Alembic 트랜잭션 내에서 실행되어 실패 시 자동 롤백 - 프로덕션 적용 전 스테이징 환경에서 반드시 테스트 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 2186626 commit a4ff441

File tree

2 files changed

+146
-3
lines changed

2 files changed

+146
-3
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""Set default values for existing items
2+
3+
Revision ID: f25407aec7a2
4+
Revises: 211d1fe6d912
5+
Create Date: 2025-10-10 02:55:21.896633
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = 'f25407aec7a2'
14+
down_revision = '211d1fe6d912'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade() -> None:
20+
# 기존 아이템의 stock이 NULL인 경우 0으로 설정
21+
op.execute("""
22+
UPDATE items
23+
SET stock = 0
24+
WHERE stock IS NULL
25+
""")
26+
27+
# 기존 아이템의 price가 NULL인 경우 1000.00으로 설정 (예시 기본값)
28+
op.execute("""
29+
UPDATE items
30+
SET price = 1000.00
31+
WHERE price IS NULL
32+
""")
33+
34+
35+
def downgrade() -> None:
36+
# downgrade 시에는 데이터를 되돌리지 않음
37+
# 실제 프로덕션에서는 신중하게 결정해야 함
38+
pass

plan.md

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,114 @@ docker-compose run --rm app1 alembic current
234234
- nullable 컬럼으로 하위 호환성 유지
235235
- 실패 시 자동 중단으로 안전성 확보
236236

237-
#### 6-4. 데이터 마이그레이션
238-
- [ ] 데이터 변환 마이그레이션 작성
239-
- [ ] op.execute() 사용법
237+
#### 6-4. 데이터 마이그레이션 ✅
238+
스키마 변경이 아닌 데이터 변환을 위한 마이그레이션을 작성했습니다.
239+
240+
**시나리오:**
241+
- 이전 마이그레이션에서 price, stock 컬럼을 nullable로 추가
242+
- 기존 데이터에는 NULL 값이 들어있음
243+
- 이 마이그레이션에서 기본값을 설정
244+
245+
**마이그레이션 생성:**
246+
```bash
247+
# --autogenerate 없이 수동 생성 (데이터 변환이므로)
248+
alembic revision -m "Set default values for existing items"
249+
```
250+
251+
**작성한 데이터 마이그레이션 (f25407aec7a2):**
252+
```python
253+
def upgrade() -> None:
254+
# 기존 아이템의 stock이 NULL인 경우 0으로 설정
255+
op.execute("""
256+
UPDATE items
257+
SET stock = 0
258+
WHERE stock IS NULL
259+
""")
260+
261+
# 기존 아이템의 price가 NULL인 경우 1000.00으로 설정
262+
op.execute("""
263+
UPDATE items
264+
SET price = 1000.00
265+
WHERE price IS NULL
266+
""")
267+
268+
269+
def downgrade() -> None:
270+
# downgrade 시에는 데이터를 되돌리지 않음
271+
# 실제 프로덕션에서는 신중하게 결정해야 함
272+
pass
273+
```
274+
275+
**op.execute() 사용법:**
276+
277+
1. **직접 SQL 실행**
278+
```python
279+
op.execute("UPDATE items SET stock = 0 WHERE stock IS NULL")
280+
```
281+
282+
2. **복잡한 쿼리 (멀티라인)**
283+
```python
284+
op.execute("""
285+
UPDATE items
286+
SET price = CASE
287+
WHEN category = 'premium' THEN 5000
288+
ELSE 1000
289+
END
290+
WHERE price IS NULL
291+
""")
292+
```
293+
294+
3. **여러 SQL 문 실행**
295+
```python
296+
op.execute("INSERT INTO logs (message) VALUES ('Migration started')")
297+
op.execute("UPDATE items SET status = 'active'")
298+
op.execute("INSERT INTO logs (message) VALUES ('Migration completed')")
299+
```
300+
301+
4. **조건부 실행**
302+
```python
303+
from sqlalchemy import text
304+
305+
connection = op.get_bind()
306+
result = connection.execute(text("SELECT COUNT(*) FROM items"))
307+
count = result.scalar()
308+
309+
if count > 0:
310+
op.execute("UPDATE items SET stock = 0 WHERE stock IS NULL")
311+
```
312+
313+
**데이터 마이그레이션 vs 스키마 마이그레이션:**
314+
315+
| 구분 | 스키마 마이그레이션 | 데이터 마이그레이션 |
316+
|------|---------------------|---------------------|
317+
| 목적 | 테이블/컬럼 구조 변경 | 데이터 변환/정제 |
318+
| 생성 방법 | --autogenerate | 수동 작성 |
319+
| 예시 | CREATE TABLE, ADD COLUMN | UPDATE, INSERT |
320+
| 롤백 | 자동 생성 | 수동 작성 필요 |
321+
322+
**주의사항:**
323+
324+
1. **성능 고려**
325+
- 대용량 데이터는 배치 처리 고려
326+
- 인덱스가 없는 컬럼 업데이트 시 느릴 수 있음
327+
328+
2. **트랜잭션**
329+
- Alembic은 기본적으로 트랜잭션 안에서 실행
330+
- 실패 시 자동 롤백됨
331+
332+
3. **downgrade 작성**
333+
- 데이터 마이그레이션의 downgrade는 복잡
334+
- 실제로는 백업 후 복원하는 것이 안전
335+
336+
4. **테스트**
337+
- 프로덕션 적용 전 반드시 스테이징 환경에서 테스트
338+
- 데이터 양에 따른 실행 시간 측정
339+
340+
**학습 포인트:**
341+
- op.execute()로 직접 SQL 실행 가능
342+
- 스키마 변경과 데이터 변환을 분리하는 것이 안전
343+
- 데이터 마이그레이션은 수동 작성이 필요
344+
- downgrade는 항상 가능한 것은 아님 (특히 데이터 삭제 시)
240345

241346
### 다음 단계 계획
242347
- [ ] 모니터링 및 로깅 추가

0 commit comments

Comments
 (0)