본문 바로가기
Everyday Study

2024.09.10(화) { flush(), dirty, 스냅샷, 데이터베이스 정규화 }

by xogns93 2024. 9. 10.

JPA에서 flush()

 

JPA에서 flush()는 영속성 컨텍스트(Persistence Context)에 있는 엔티티 상태 변화를 데이터베이스에 즉시 반영하는 메서드입니다. 이를 통해 메모리 상에서 관리되던 엔티티의 변경 사항을 데이터베이스에 동기화합니다.

 

영속성 컨텍스트와 플러쉬

JPA는 영속성 컨텍스트라는 메커니즘을 통해 엔티티 객체의 상태 변화를 관리합니다. 엔티티 객체가 변경되면, JPA는 즉시 데이터베이스에 반영하지 않고 영속성 컨텍스트에서 이를 관리하다가 적절한 시점에 한꺼번에 데이터베이스에 반영합니다. 이 시점을 제어하는 메서드가 바로 flush()입니다.

flush()의 작동 방식

  1. 영속성 컨텍스트에 있는 변경된 엔티티들이 데이터베이스로 즉시 반영됩니다.
    • insert, update, delete 쿼리가 즉시 실행되어 데이터베이스에 적용됩니다.
  2. 하지만, 트랜잭션은 종료되지 않습니다. 즉, flush()가 실행되더라도 트랜잭션이 커밋되지 않으면 롤백이 가능합니다.
  3. 자동 실행 시점: flush()는 명시적으로 호출하지 않더라도, 몇 가지 조건에서 자동으로 실행됩니다.
    • 트랜잭션이 커밋될 때
    • JPQL 쿼리 Native Query가 실행될 때
    • 영속성 컨텍스트에서 데이터의 상태를 명시적으로 반영하고 싶을 때

flush()의 필요성

때로는 트랜잭션이 끝나기 전에, 즉 커밋하기 전에 변경 사항을 데이터베이스에 반영해야 하는 경우가 있습니다. 이럴 때 flush()를 호출하여 영속성 컨텍스트에 있는 변경 사항을 미리 데이터베이스에 반영할 수 있습니다. 그러나 트랜잭션이 종료되지 않았으므로, 이후 트랜잭션에서 문제가 발생하면 여전히 롤백할 수 있습니다.

flush()와 commit()의 차이점

  • flush(): 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하지만, 트랜잭션을 종료하지 않습니다. 이후 롤백이 가능합니다.
  • commit(): 트랜잭션을 종료하면서 모든 변경 내용을 확정 짓습니다. 커밋이 되면 더 이상 롤백할 수 없습니다.

파일시스템에서 "dirty" 라는 용어

 

파일 시스템에서 **"dirty"**라는 용어는 수정되었지만 아직 영구 저장소(예: 디스크)에 기록되지 않은 데이터를 의미합니다. 주로 캐시 시스템이나 메모리 관리에서 사용되며, 파일 시스템의 버퍼 또는 캐시에서 수정된 데이터를 가리킬 때 사용됩니다.

주요 개념

  1. Dirty 페이지/블록: 운영체제나 데이터베이스에서 메모리에 있는 데이터가 수정되었지만, 아직 디스크에 기록되지 않은 상태의 페이지 또는 블록을 말합니다.
  2. Dirty 비트: 해당 페이지나 블록이 수정되었다는 사실을 추적하기 위해 사용하는 플래그입니다. 이 비트가 설정되면, 그 페이지나 블록이 수정되었음을 나타냅니다.
  3. Flush (플러쉬): Dirty 데이터를 실제 디스크에 기록하여 깨끗한 상태로 만드는 과정입니다. 이 과정은 데이터 일관성 및 무결성을 보장하기 위해 주기적으로 또는 특정 상황에서 실행됩니다.

Dirty 데이터의 흐름

  1. 데이터가 메모리(캐시)에 로드됩니다.
  2. 그 데이터가 수정되면, 해당 데이터는 dirty 상태가 됩니다.
  3. 이 dirty 상태의 데이터는 메모리에 남아있지만, 아직 디스크에 기록되지 않은 상태입니다.
  4. 일정 시간이 지나거나, 메모리가 부족하거나, 명시적으로 플러쉬가 실행될 때, dirty 데이터는 디스크에 기록되며 clean 상태로 전환됩니다.

Dirty 상태의 문제점

  • 데이터 손실 위험: 만약 dirty 데이터가 디스크에 기록되기 전에 시스템이 갑자기 종료되거나 충돌이 발생하면, 해당 수정된 데이터는 손실될 수 있습니다.
  • 성능 최적화: Dirty 상태는 성능 최적화와도 관련이 있습니다. 데이터가 즉시 디스크에 기록되지 않으면, 여러 수정 작업을 한 번에 처리할 수 있어 디스크 입출력(I/O) 비용을 줄일 수 있습니다. 하지만 플러쉬를 지연시키면 데이터 손실 가능성이 커집니다.

예시: 파일 시스템의 캐시와 Dirty 데이터

파일 시스템에서 읽고 쓰는 데이터는 종종 디스크에서 메모리로 캐시됩니다. 파일을 수정하는 경우, 수정된 데이터는 메모리 캐시에 유지되며 디스크에 즉시 쓰이지 않을 수 있습니다. 이때 캐시된 데이터가 dirty 데이터가 됩니다. 운영체제는 dirty 데이터를 디스크에 기록할 시점을 관리하며, 이 과정을 **플러쉬(flush)**라고 합니다.

결론

Dirty는 파일 시스템이나 메모리에서 수정되었지만 아직 영구 저장 장치(예: 디스크)에 반영되지 않은 데이터를 가리킵니다. 이런 데이터는 운영체제나 애플리케이션이 플러쉬 작업을 통해 디스크에 기록되기 전까지 dirty 상태로 유지됩니다.

 

 


스냅샷(snapshot)

 

 

스냅샷이란?

스냅샷은 어떤 시점의 데이터를 복사해서 기억해두는 것이에요. 그 시점의 데이터 상태를 나중에 다시 볼 수 있도록 저장해둔다고 생각하면 돼요.

스냅샷의 역할

  1. 일관된 데이터 보기:
    • 예를 들어, 당신이 은행 앱에서 내 계좌 잔고를 확인하려고 해요. 그런데 다른 사람이 같은 시간에 그 계좌에 돈을 입금하거나 출금하는 작업을 한다고 상상해 보세요. 잔고가 계속 변할 텐데, 당신은 변하지 않는, 일관된 잔고 정보를 보고 싶을 거예요.
    • 이때 스냅샷을 사용하면, 잔고가 변하기 전 어느 한 시점의 잔고 상태를 그대로 유지해서 볼 수 있어요. 그러면 누군가 계좌에 돈을 넣거나 빼는 도중에도, 당신은 일관된 잔고를 확인할 수 있죠.
  2. 잘못된 작업 되돌리기:
    • 프로그램이 작업을 하다가 문제가 생기면, 스냅샷을 사용해 문제 생기기 전 상태로 되돌릴 수 있어요. 즉, 미리 저장해둔 상태로 돌아가는 것이죠.
    • 예를 들어, 글을 쓰다가 갑자기 컴퓨터가 멈추거나 저장이 안 되는 상황이 발생하면, 작업을 잃어버릴 수 있잖아요. 하지만 5분마다 자동으로 문서를 저장(스냅샷을 찍는 것처럼)했다면, 문제가 생기기 전 5분 전 상태로 되돌아갈 수 있는 것과 비슷해요.

스냅샷을 쓰는 상황

  • 트랜잭션 처리 중: 여러 작업을 동시에 처리할 때, 한 작업이 진행되는 중간에 다른 작업이 데이터를 바꾸지 않도록 스냅샷을 만들어서 그 상태를 기준으로 작업을 마치게 해요. 그러면 한 작업이 끝나기 전에 다른 작업 때문에 데이터가 엉망이 되는 걸 막을 수 있죠.
  • 백업과 복구: 만약 데이터베이스가 문제가 생기면, 저장해둔 스냅샷을 사용해서 특정 시점으로 데이터를 되돌릴 수 있어요. 예를 들어, 데이터베이스에 실수로 잘못된 데이터를 입력했다면, 그 전에 찍어둔 스냅샷으로 돌아가서 오류를 복구할 수 있는 거예요.

간단한 비유

스냅샷은 마치 비디오 게임에서 체크포인트 같은 역할을 해요. 게임을 하다가 실수로 잘못된 길로 가거나 죽었을 때, 체크포인트로 돌아가 다시 시작할 수 있잖아요? 스냅샷도 비슷하게, 데이터베이스 작업을 하다가 문제가 생기면 그 전에 저장해둔 상태로 되돌아갈 수 있게 해주는 기능이에요.

이해하기 쉽게 정리하면, 스냅샷은 "지금 상태를 기억해놨다가, 나중에 문제가 생기면 그 상태로 돌아갈 수 있게 해주는 것"입니다.

 


데이터베이스 정규화 (Normalization)

 

정규화는 데이터베이스 설계 시 데이터 중복을 최소화하고, 데이터의 일관성 무결성을 유지하기 위해 데이터를 체계적으로 나누는 과정

정규화를 통해 데이터를 작은 테이블로 나누고, 테이블 간에 관계를 정의해서 데이터의 중복을 줄이고 업데이트, 삭제, 삽입 시 일관성 있는 작업을 할 수 있게 돕습니다.

정규화의 목적

  • 데이터 중복 최소화: 데이터를 여러 곳에 중복 저장하지 않음으로써 저장 공간을 절약하고, 데이터 불일치 문제를 해결.
  • 데이터 무결성 보장: 데이터가 일관되게 유지되도록 하여 잘못된 데이터가 들어가는 것을 방지.
  • 데이터 업데이트 효율성 향상: 특정 데이터를 수정할 때 하나의 테이블만 수정하면 되도록 설계하여, 업데이트를 쉽게 하고 성능을 높임.

정규화 단계 (Normal Forms)

정규화는 여러 단계로 나눌 수 있어요. 단계가 올라갈수록 데이터 중복을 더 많이 줄일 수 있지만, 그만큼 테이블이 더 세분화되기도 합니다.

  1. 제 1정규형 (1NF):
    • 중복된 열이나 그룹화된 데이터를 제거하고, 각 열에 원자값(하나의 값만 포함된 데이터)을 저장.
    • 예시: 전화번호 칸에 여러 전화번호를 콤마로 구분하여 넣지 않고, 각각의 전화번호를 따로 관리.
  2. 제 2정규형 (2NF):
    • 1정규형을 만족하면서 부분적 종속성을 제거. 즉, 기본 키의 일부에만 종속된 데이터를 별도의 테이블로 분리.
    • 예시: 학생 정보 테이블에 과목과 성적을 함께 저장하지 않고, 과목 정보를 별도 테이블로 나누어 관리.
  3. 제 3정규형 (3NF):
    • 2정규형을 만족하면서 이행적 종속성을 제거. 즉, 기본 키에 의존하지 않는 데이터를 별도의 테이블로 분리.
    • 예시: 학생 테이블에 주소와 우편번호가 함께 저장되어 있으면, 우편번호와 주소 간의 종속성을 제거하고 우편번호를 별도 테이블로 분리.

정규화의 문제점 (과도한 정규화)

정규화를 너무 많이 진행하면 다음과 같은 문제가 발생할 수 있어요:

  1. 과도한 테이블 분할: 데이터를 지나치게 세분화하여 너무 많은 테이블이 생성될 수 있고, 이로 인해 복잡한 조인이 발생하여 성능이 저하될 수 있어요.
  2. 성능 저하: 데이터를 조회할 때 여러 테이블을 조인해야 하므로, 조회 속도가 느려질 수 있습니다.
  3. 관리의 어려움: 너무 많은 테이블과 관계가 복잡해지면, 데이터베이스 관리가 어려워질 수 있습니다.

정규화의 해결 방법 (비정규화, Denormalization)

비정규화는 정규화된 데이터를 적절히 역정규화하여, 데이터 중복을 일부 허용하고 성능을 향상시키는 기법입니다. 정규화가 데이터를 너무 세분화해서 발생하는 성능 문제를 해결하는 데 사용됩니다.

비정규화 전략:

  1. 자주 사용하는 데이터를 통합:
    • 자주 조인되는 테이블을 통합하여, 성능을 개선할 수 있습니다. 예를 들어, 조회가 자주 일어나는 학생과 과목 테이블을 합치는 방법을 사용할 수 있습니다.
  2. 중복 데이터 허용:
    • 일부 중복을 허용해서 성능을 개선할 수 있어요. 예를 들어, 사용자의 나이를 조회할 때, 매번 생년월일로부터 계산하는 대신, 나이를 별도로 저장하고 주기적으로 업데이트할 수 있습니다.
  3. 조회 속도 향상을 위한 캐싱:
    • 자주 사용하는 데이터를 캐시에 저장하여, DB 조회 부담을 줄일 수 있습니다.
  4. 조인을 피하기 위한 컬럼 추가:
    • 자주 조회되는 데이터를 포함한 새로운 컬럼을 추가해서 조인 없이 데이터를 빠르게 조회할 수 있습니다.

정규화와 비정규화의 균형

정규화는 데이터 무결성과 일관성을 유지하는 데 중요하지만, 데이터베이스 성능 요구 사항에 따라 비정규화도 고려해야 해요. 적절히 정규화된 데이터 모델을 유지하면서, 성능이 중요한 부분에서는 비정규화를 적용하여 성능 데이터 무결성 사이의 균형을 맞추는 것이 중요합니다.

요약

  • 정규화는 데이터의 중복을 줄이고, 일관성을 높이기 위해 테이블을 나누는 과정.
  • 비정규화는 성능 향상을 위해 일부 중복을 허용하고 테이블을 합치는 작업.
  • 적절한 정규화와 비정규화의 균형을 맞춰서 성능과 데이터 무결성을 유지하는 것이 중요합니다.