본문 바로가기
정보관리(데이터베이스, DB)/DB

고아(Orphan) 데이터 및 고아(Orphan) 데이터 이관

by 3604 2025. 10. 23.
728x90
고아 데이터 이관 시 처리 방법?
 
 
 
고아 데이티 이관 처리 방법
고아 데이터(Orphaned Data) 이관 시 처리 방식은 데이터의 성격과 시스템 요구사항에 따라 다르지만, 일반적으로 다음과 같은 방식으로 처리됩니다:

 고아 데이터란?

고아 데이터는 부모 엔티티와의 연관관계가 끊어진 자식 데이터를 의미합니다. 예를 들어, 부모 테이블의 레코드가 삭제되었는데도 불구하고, 자식 테이블에 해당 레코드에 대한 참조가 남아있는 경우가 이에 해당합니다.

🔍 고아 데이터 이관 시 처리 방법

1. 고아 객체 제거 (Orphan Removal)

  • JPA 등 ORM 프레임워크에서는 orphanRemoval = true 옵션을 통해 부모 엔티티에서 자식 엔티티의 참조를 제거하면, 해당 자식 데이터를 자동으로 삭제할 수 있습니다.
  • 이 방식은 데이터 정합성을 유지하면서도, 불필요한 데이터를 제거하는 데 유용합니다.
  • 예: parent.getChildList().remove(child) 시, DB에서도 자동 삭제됨.

2. 영속성 전이(Cascade) 설정

  • CascadeType.REMOVE 또는 CascadeType.ALL을 설정하면, 부모 엔티티 삭제 시 자식 엔티티도 함께 삭제됩니다.
  • 이는 고아 데이터 발생 자체를 방지하는 방식입니다.

3. 이관 전 정리 작업

  • 데이터 이관 전에 고아 데이터를 탐색하고 정리하는 프로세스를 거칩니다.
  • SQL 쿼리를 통해 부모 참조가 없는 자식 데이터를 찾아 삭제하거나, 별도의 보관 테이블로 이관할 수 있습니다.

4. 정책 기반 처리

  • 일부 시스템(예: IBM BAW)에서는 고아 토큰을 관리하기 위한 마이그레이션 정책 파일을 생성하여, 이관 시 고아 데이터를 자동으로 삭제하거나 재할당하는 방식을 사용합니다.

⚠️ 주의사항

  • 외래키 무결성 제약이 걸려 있는 경우, 부모 없이 자식 데이터만 남아 있으면 삭제나 이관 시 오류가 발생할 수 있습니다.
  • 따라서 이관 전 제약 조건을 일시적으로 해제하거나, 순서에 맞게 데이터를 처리해야 합니다.

✅ 요약

Table
 
처리 방식설명적용 시점
orphanRemoval=true 부모와 연관 끊긴 자식 자동 삭제 JPA 엔티티 설계 시
CascadeType.REMOVE 부모 삭제 시 자식도 삭제 JPA 엔티티 설계 시
사전 정리 고아 데이터 탐색 및 삭제 이관 전
정책 파일 기반 처리 고아 데이터 정책 적용 이관 도구 또는 프레임워크 지원 시

필요하다면, 실제 시스템 환경(JPA, DB, 이관 도구 등)에 맞춰 구체적인 처리 방식을 설계해드릴 수 있습니다.
 
Share
 
 
실제 시스템 환경(JPA, DB, 이관 도구 등)에 맞춰 구체적인 처리 방식을 설계해줘
Edit
 
Share
 
아래는 “실제 운영 중인 시스템”을 기준으로
  • JPA (Spring Data JPA 3.x)
  • PostgreSQL 15
  • 이관 도구: Flyway + 배치 Job (Spring Batch 5)
    를 사용한다는 전제로 고아(Orphan) 데이터를 0%로 만들면서 이관하는 End-to-End 설계서입니다.
    (Oracle, MySQL으로 DB를 바꿔도 구조는 동일합니다.)

1. 목표 정의

Table
 
항목값
고아 허용률 0% (이관 후 FK로 검증 시 0건)
다운타임 30분 이내 (Blue-Green 배포 기준)
롤백 가능 시점 이관 배치 실패 시 5분 이내 원복
보존 기간 삭제 전 30일간 보관 테이블 보관

2. 도메인 모델 예시

java
 
@Entity
@Table(name = "orders")
public class Order {
    @Id private Long id;

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<OrderItem> items = new ArrayList<>();
}

@Entity
@Table(name = "order_items")
public class OrderItem {
    @Id private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "order_id", foreignKey = @ForeignKey(name = "fk_item_order"))
    private Order order;
}
  • orphanRemoval=true → 운영 코드에서 이미 고아 발생 차단
  • 그러나 이관 대상은 기존 레거시 데이터이므로 별도 정리 필요

3. 이관 전 체크리스트 (Pre-Migration)

3-1. 고아 탐지 SQL (PostgreSQL 기준)

sql
 
-- 1) order_items에 order_id가 없는 레코드
SELECT item.*
FROM   order_items item
LEFT   JOIN orders o ON o.id = item.order_id
WHERE  o.id IS NULL;

-- 2) FK가 DISABLE돼 있을 수 있으므로 추가 검증
SELECT conname
FROM   pg_constraint
WHERE  contype = 'f'
  AND  conname = 'fk_item_order'
  AND  NOT convalidated;
결과 건수 = 0 이어야 함.
0건이 아니면 4단계 “고리 제거” 실행

3-2. 운영 중단점 결정

  • Blue-Green 배포 → Green 환경으로 트래픽 스위치 직전에 마지막 증분 데이터 적재
  • 증분 구간: modified_date < SWITCHOVER_TIME - 5min (5분 버퍼)

4. 고리 제거 배치 (OrphanCleanupJob)

Spring Batch Job 하나를 만들어 이관 전날 밤 실행.
Table
 
Step설명SQL/코드
1 고아 백업 CREATE TABLE order_items_orphan_bak AS SELECT * FROM order_items WHERE order_id NOT IN (SELECT id FROM orders);
2 고아 삭제 DELETE FROM order_items WHERE order_id NOT IN (SELECT id FROM orders);
3 FK 재활성화 ALTER TABLE order_items VALIDATE CONSTRAINT fk_item_order;
4 건수 기록 INSERT INTO migration_log(table_name, orphan_cnt, deleted_at) VALUES ('order_items', @@rowcount, now());
  • 청크 크기: 10,000 (대용량 시 커서 기반)
  • 트랜잭션: 1 청크당 1 트랜잭션 → 실패 시 재시도 3회
  • 스킵 정책: DeadLock 발생 시 50ms 지연 후 3회 재시도

5. 스키마 이관 (Flyway)

V202510230100__baseline.sql
  • Green 환경 신규 스키마 생성
  • FK는 모두 DEFERRABLE INITIALLY DEFERRED 로 생성
    → 데이터 적재 중 일시적 무순서 허용, 커밋 직전 검증

6. 데이터 이관 배치 (MigrateMainJob)

Table
Step기능비고
1 Source 테이블 → CSV DUMP COPY (SELECT * FROM orders WHERE modified_date <= :cutoff) TO '/data/orders.csv' CSV;
2 Green DB 적재 COPY orders FROM '/data/orders.csv' CSV;
3 아이템 적재 동일
4 FK 검증 SET CONSTRAINTS ALL IMMEDIATE; → 실패 시 롤백
5 시퀀스 동기화 SELECT setval('orders_id_seq', max(id)) FROM orders;
  • 전체 Step은 JobRepository에 결과 저장 → 실패 시 Slack 알림 + 자동 롤백
  • 청크 기반 병렬 처리: 4 Thread, 1 청크 = 5,000건

7. 검증 (ValidationJob)

sql
 
-- 1) 고아 재확인
SELECT COUNT(*)
FROM   order_items oi
LEFT   JOIN orders o ON o.id = oi.order_id
WHERE  o.id IS NULL;

-- 2) Row count 비교
SELECT 'orders', count(*) FROM orders
UNION ALL
SELECT 'order_items', count(*) FROM order_items;
  • 결과를 검증 테이블에 저장 → 0건이면 SUCCESS, 1건 이상이면 FAIL

8. 롤백 플랜

  • Green 환경 교체 전 → Blue 그대로 유지
  • 실패 시 Green DB Drop → Blue 유지 → 5분 내 트래픽 복구
  • 보관 테이블(*_orphan_bak)은 30일 후 VACUUM으로 물리 삭제

9. 자동화 흐름 (CI/CD)

bash
 
1. git tag: release/1.2.0
2. Jenkinsfile
   - stage: flyway-migrate-green
   - stage: orphan-cleanup-job   (Spring Batch 호출)
   - stage: migrate-main-job
   - stage: validation-job
   - stage: switch-traffic (k8s patch)
3. 실패 시 자동 롤백 스크립트 실행

10. 운영 이후

  • JPA Entity는 이미 orphanRemoval=true 이므로 신규 데이터에 대해선 고아 0% 유지
  • 매주 일요일 FK 검증 리포트를 Jenkins 로 자동 생성 → 0건이 아닐 경우 PagerDuty 알림

11. 필요 스크립트 모음 (Git 레포 구조)

 
migration/
 ├─ flyway/
 │   └─ sql/
 ├─ batch/
 │   ├─ OrphanCleanupJob.java
 │   ├─ MigrateMainJob.java
 │   └─ ValidationJob.java
 └─ scripts/
     ├─ detect_orphan.sh
     ├─ rollback_green.sh
     └─ report_weekly.sh

12. 한 줄 요약

이관 전날 밤 고아를 탐지→백업→삭제→FK 재활성화하고,
이관 당일 증분 데이터를 Blue-Green으로 스위치 직전에 병렬 적재+FK 검증하며,
실패 시 5분 내 Blue로 롤백하는 Spring Batch 기반 무고아(0%) 이관 파이프라인
필요하면 위 Job 클래스 소스코드나 Flyway SQL, Helm chart까지 제공해드릴 수 있습니다.
728x90