개발기술/데이터베이스

데이터 베이스 최적화 고려요인

bsh6226 2024. 8. 7. 13:02

저장되는 데이터 타입을 고려

  • 문자열인지, 숫자인지, 숫자의 범위인지, 문자열의 길이는 어떻게 되는지
  • 문자열과 숫자: 데이터의 성격에 따라 적절한 타입을 선택합니다. 예를 들어, 숫자 타입은 정수(INTEGER), 부동 소수점(FLOAT, DOUBLE), 고정 소수점(DECIMAL) 등이 있으며, 각 타입은 저장할 수 있는 값의 범위와 정밀도가 다릅니다. 문자열의 경우, 고정 길이(CHAR)와 가변 길이(VARCHAR)를 구분하여 사용해야 하며, 길이 제한을 설정함으로써 메모리 사용을 최적화할 수 있습니다.
    • 데이터 타입 선정 기준: 데이터의 최대 크기, 사용 빈도, 쿼리의 종류에 따라 타입을 선정합니다. 예를 들어, ID 값이나 코드 값은 VACHAR보다는 CHAR로 고정하는 것이 검색 속도 향상에 도움이 될 수 있습니다.

1. 숫자 데이터 타입의 성능 고려사항

  • 정수 (INTEGER): 정수는 SMALLINT, INTEGER, BIGINT와 같이 다양한 범위가 있습니다. 가능한 한 작은 범위의 정수 타입을 사용하면 메모리 효율성이 향상되고, 데이터베이스 캐시 활용도가 높아져 성능이 개선됩니다.
  • 부동 소수점 (FLOAT, DOUBLE): 크기와 정밀도에 따라 선택됩니다.  부동 소수점 연산은 정수 연산보다 CPU 자원을 더 많이 사용하므로, 필요한 경우에만 사용해야 합니다.
  • 고정 소수점 (DECIMAL): 금융 계산과 같이 정확한 소수점 연산이 필요한 경우에 사용됩니다. DECIMAL은 부동 소수점보다 처리 속도가 느릴 수 있지만, 정확도가 더 중요할 때 선택됩니다.

2. 문자열 데이터 타입의 성능 고려사항

  • 고정 길이 (CHAR): 고정 길이 문자열은 항상 동일한 크기의 공간을 차지합니다. 이로 인해 메모리 관리가 간단해지고, 문자열 검색이 빠르게 수행될 수 있습니다. 특히 고정된 형식의 데이터 (예: 국가 코드, 포맷이 정해진 일련번호 등)를 저장할 때 유리합니다.
  • 가변 길이 (VARCHAR): VARCHAR 타입은 실제 데이터에 필요한 만큼의 공간만 사용합니다. 이는 공간 효율성을 높이지만, 메모리 재배치나 추가적인 메모리 관리 오버헤드를 발생시킬 수 있습니다. 

3. 성능 최적화를 위한 추가 전략

  • 인덱싱 전략: 적절한 데이터 타입 선택은 인덱스 성능에도 큰 영향을 미칩니다. 예를 들어, INTEGER 타입의 인덱스는 VARCHAR 타입의 인덱스보다 조회 성능이 좋습니다. 인덱스 키의 크기가 작을수록 더 많은 인덱스 항목들을 메모리에 유지할 수 있으며, 따라서 검색 성능이 향상됩니다.
  • 데이터 정규화와 비정규화: 데이터베이스 설계 시 데이터 정규화를 통해 중복을 최소화하고 무결성을 유지할 수 있지만, 조회 성능을 위해 일부 데이터를 비정규화하는 전략도 고려할 수 있습니다. 비정규화는 쿼리를 단순화시키고 조인 연산을 줄여 성능을 향상시킬 수 있습니다.

 

데이터 테이블간의 관계 설정

 

단방향 관계 

  • JPA에서 @OneToOne, @ManyToOne 으로 관계가 설정되어있지만 Collection<Entity>가아니라 Entity를 필드로 갖는경우. 이 경우, userEntity에서 ReservationEntity를 바로 찾을 수 없고 ReservationRepository에서만 찾을 수 있어 단방향이다. (단, SQL의 동작은 동일함.
public class ReservationEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long id;
    String reservationId;
    @ManyToOne
    @JoinColumn(name = "userId", referencedColumnName = "userId",
            nullable = false)
    UserEntity userEntity;
 

양방향 관계

  • JPA에서 @OneToOne, @ManyToOne 으로 관계가 설정되어있지만 Entity를 필드로 갖는게 아니라  Collection<Entity>를 갖는 경우. 이 경우, userEntity에서 ReservationEntity를 바로 찾을 수 없고 ReservationRepository에서만 찾을 수 있어 단방향이다. (단, SQL의 동작은 동일함.
    • 추가 쿼리 발생 가능성: 양방향 관계에서는 두 엔티티가 서로를 참조합니다. 이는 때때로 추가적인 쿼리를 발생시킬 수 있습니다. 
    • 지연 로딩(Lazy Loading): JPA에서는 성능 최적화를 위해 지연 로딩(Lazy Loading)을 사용할 수 있습니다. 양방향 관계에서는 지연 로딩을 잘 활용하지 않으면, 필요 이상의 데이터를 메모리에 로드하게 되어 성능이 저하될 수 있습니다
@Entity
public class UserEntity {
  @OneToMany(mappedBy = "userEntity", cascade = CascadeType.ALL)
  private Set<ReservationEntity> reservations = new HashSet<>();

  // other fields and methods...

 

 

데이터 테이블 간의 탐색

 

테이블간의 관계에 의해서 여러번 DB에 접근하는 경우가 있다. 이경우 N+1 Problem이 발생하지 않도록 주의하는 것이 주요한 데이터베이스 최적화 전략이라고 할 수 있겠다. 

  가령, User가 여러개의 store이 있고 store은 여러개의 transaction이 있는 경우, user로 특정 transaction을 접근하려는 경우 userEntity에서 storeEntity를 찾고, storeEntity에서 Transaction을 찾아야한다.

이런경우에 LazyLoading에 의해서 N+1 문제가 발생할 수 잇다.

 

Lazy Loading의 동작 원리: Lazy Loading은 객체를 처음 조회할 때 실제 데이터베이스에서 연관된 데이터를 로드하지 않고, 연관된 객체에 실제로 접근할 때 필요한 데이터를 데이터베이스에서 조회하는 방식입니다.

  • UserEntity가 ReservationEntity를 연관 테이블로써, 필드로 갖지만 UserEntity를 호출했을때 reservationEntity를 바로 조회하지 않음. Userentity.getReservationEntity() 코드가 발견되어서야만 쿼리를 동작시킴.
  • 이는 메모리 사용을 줄이고 성능을 최적화하기 위한 기법으로, 주로 조회(Selection) 작업에 사용됩니다. 조회(Selection) 작업이 생성(Create), 수정(Update), 삭제(Delete) 작업과 본질적으로 다른 성격을 가지기 때문에 Lazy Loading이 오직 조회 작업에서만 작동한다. 생성, 수정, 삭제 작업에서는 데이터베이스의 상태를 변경하는 것이 주된 목표이므로, Lazy Loading이 필요하지 않습니다. 이 작업에서는 특정 엔티티와 연관된 데이터를 지연 로딩할 이유가 없고, 오히려 명확한 데이터를 기반으로 작업을 수행해야 합니다.

 

N+1 문제:

  • Lazy Loading을 사용할 때 가장 많이 발생하는 문제 중 하나입니다. 예를 들어, 한 번의 쿼리로 부모 엔티티를 가져온 후, 자식 엔티티를 각각 Lazy Loading으로 가져오게 되면, 부모 엔티티 수에 비례하여 추가적인 쿼리가 발생합니다. 그러니 어차피 N+1번 테이블에서 가져올것 한번에 조회하는 것이 Latency를 줄이는 길이라는 것. LazyLoading을 할시에, N+1번 DB에 접근하는 것과 동일하기 때문임.
    • 아래의 예에서 reviewEntity를 통해 StoreEntity를 조회하고 , PartnerEntity를 조회하면 N+1 Problem의 전형이다.
if(!(Objects.equals(reviewEntity.getUserEntity().getUserId(), memberId)
        || Objects.equals(reviewEntity.getStoreEntity().getPartnerEntity().getPartnerId(), memberId))){
    throw new CustomException(ErrorCode.MEMBERID_REVIEWUSER_UNMATCHED);

 

 

최적화방안

 

  • 최적화방안1 : Fetch with JPQL or QueryDSL을 통해서 EagerLoading Method 생성
    • LazyLoading을 통해 collection을 조회하고 해당 collection을 loop하게 되면 N+1번 데이터베이스를 조회하는 문제가 발생한다. 이를 예방하기 위해서 N개의 Entity를 일괄 불러오는 쿼리를 따로 만들수 있다
  •  최적화방안2 : N+1문제 뿐만아니라 JoinFetch를 통해서 UserEntity, StoreEntity, PartnerEntity를 각각 호출하지 않아도 일괄적으로 원하는 값을 조회해낼 수 있다. 
@Query("SELECT r FROM ReviewEntity r JOIN FETCH r.userEntity JOIN FETCH r.storeEntity s JOIN FETCH s.partnerEntity WHERE r.id = :reviewId")
ReviewEntity findByIdWithUserAndPartner(@Param("reviewId") String reviewId);

 

데이터의 규모는 어떻게 되는지

  • 매일 1천건? 1만건? 수십만건?
  • 데이터 규모 측정: 예상되는 데이터의 총량과 일별, 월별 증가량을 예측합니다. 이를 기반으로 데이터베이스 서버의 저장 용량, 메모리, CPU 성능 등을 계획해야 합니다.
  • 확장 전략: 데이터베이스가 수평적 또는 수직적으로 확장 가능하도록 설계합니다. 수평 확장은 여러 서버에 데이터를 분산시키는 방법으로, NoSQL 데이터베이스에서 일반적입니다. 수직 확장은 서버의 자원(디스크, CPU, 메모리)을 증가시키는 것입니다.

1. 데이터 규모 측정 및 예측

  • 용량 계획: 데이터베이스의 초기 크기와 예상되는 성장률을 바탕으로, 적절한 저장소 용량을 확보해야 합니다. 데이터베이스 성능은 디스크 용량과 밀접한 관련이 있습니다. 디스크 I/O는 데이터베이스 성능의 병목 현상을 일으킬 수 있는 주요 요소 중 하나이므로, 충분한 I/O 성능과 용량을 갖춘 스토리지 시스템을 선택하는 것이 중요합니다.
  • 성능 모니터링: 정기적으로 데이터베이스 성능을 모니터링하고, 데이터 증가에 따라 성능 변화를 분석해야 합니다. 이는 미래의 확장 필요성을 예측하는 데 도움을 줄 수 있습니다.

2. 확장 전략

  • 수평 확장 (Scaling Out): 데이터베이스를 여러 서버에 분산하여 각 서버가 데이터의 일부를 처리하게 하는 방식입니다. 이는 데이터베이스의 부하를 분산시키고, 처리 능력을 증가시킵니다. NoSQL 데이터베이스 시스템에서는 이 방식이 자주 사용되며, 관계형 데이터베이스에서도 샤딩이나 파티셔닝을 통해 비슷한 효과를 낼 수 있습니다.
    • 샤딩: 데이터를 수평적으로 분할하여 여러 서버에 분산 저장합니다. 각 샤드는 독립적으로 데이터를 처리하고 저장하여 성능 향상과 데이터 관리의 유연성을 제공합니다.
    • 리플리케이션: 데이터의 복사본을 여러 서버에 분산하여 읽기 성능을 향상시키고, 고가용성을 보장합니다.
  • 수직 확장 (Scaling Up): 기존의 서버에 더 많은 자원(메모리, CPU, 디스크 등)을 추가하여 처리 능력을 증가시키는 방식입니다. 이는 기존 시스템을 수정하지 않고도 성능을 향상시킬 수 있는 방법이지만, 물리적 한계에 도달하면 더 이상 확장이 어려울 수 있습니다.

3. 성능 최적화 기술

  • 인덱스 최적화: 데이터의 양이 많아짐에 따라 적절한 인덱싱 전략을 수립하는 것이 중요합니다. 필요한 컬럼에 인덱스를 생성하고, 불필요한 인덱스는 제거하여 인덱스 관리 비용을 최소화합니다.
  • 쿼리 최적화: 자주 사용되는 쿼리의 성능을 분석하고 최적화합니다. 쿼리 플랜을 검토하여 비효율적인 조인이나 불필요한 데이터 접근을 줄입니다.
  • 하드웨어 최적화: SSD와 같은 고성능 스토리지를 사용하여 디스크 I/O 성능을 향상시킬 수 있습니다. 또한, 충분한 메모리를 확보하여 데이터베이스 캐싱을 극대화합니다.

 

<3> 데이터의 저장 주기는 어떻게 되는지

  • 저장단위가 영구적? 매월? 매일?
  • 영구 저장과 임시 저장: 필요에 따라 데이터를 영구적으로 저장하거나 일정 기간 후 삭제할 수 있도록 설계합니다. 예를 들어, 로그 데이터나 임시 처리 데이터는 일정 기간 후 자동으로 삭제되도록 설정할 수 있습니다.
  • 백업 및 복구 전략: 데이터의 중요도에 따라 다양한 백업 전략을 적용합니다. 중요 데이터는 매일 백업을 수행하고, 덜 중요한 데이터는 주간 또는 월간 백업을 고려할 수 있습니다.

1. 데이터 라이프사이클 관리 (DLM)

데이터 라이프사이클 관리는 데이터의 생성부터 삭제까지의 전 과정을 체계적으로 관리하는 프로세스입니다. 이를 통해 데이터의 저장 주기를 효과적으로 관리하고, 비용을 절감하며, 준수 요건을 충족할 수 있습니다.

  • 자동화된 데이터 정책: 데이터의 중요도, 접근 빈도, 법적 요구 사항 등에 따라 데이터를 자동으로 분류하고, 적절한 저장소에 할당하며, 지정된 시간이 지난 후에는 자동으로 아카이브하거나 삭제합니다.
  • 데이터 티어링: 접근 빈도가 낮은 데이터를 더 저렴한 저장 매체로 이동시키는 전략을 구현합니다. 예를 들어, 활발히 사용되지 않는 데이터는 냉각 스토리지(Cold Storage)로 옮겨 비용을 절약할 수 있습니다.

2. 백업 및 복구 전략의 세부 사항

백업 및 복구 전략은 데이터의 중요도와 가용성 요구 사항을 기반으로 세밀하게 계획되어야 합니다.

  • 백업 유형:
    • 전체 백업 (Full Backup): 모든 데이터를 백업하는 가장 기본적인 형태입니다. 가장 안전하지만 시간과 저장 공간을 많이 필요로 합니다.
    • 증분 백업 (Incremental Backup): 마지막 전체 백업 이후 변경된 데이터만 백업합니다. 저장 공간과 백업 시간을 절약할 수 있지만, 복구 과정이 복잡해질 수 있습니다.
    • 차등 백업 (Differential Backup): 마지막 전체 백업 이후 변경된 모든 데이터를 백업합니다. 증분 백업보다 복구 시간은 빠르지만, 저장 공간을 더 많이 사용합니다.

<4> 데이터의 읽기와 쓰기의 비율

  • 데이터베이스에 요청되는 연산이 어떤 방식인지? 9:1 읽기 비율
  • 읽기 중심의 시스템: 데이터베이스를 읽기 전용 복제본으로 확장하여, 읽기 요청을 분산시키고 주 데이터베이스의 부하를 줄일 수 있습니다. 캐싱을 활용하여 자주 접근하는 데이터의 읽기 성능을 향상시킬 수 있습니다.
  • 쓰기 중심의 시스템: 쓰기 작업을 최적화하기 위해 로그 구조 병합 트리(LSM-Tree)와 같은 데이터 구조를 사용하는 데이터베이스를 고려할 수 있습니다. 데이터 쓰기를 일괄 처리하거나 쓰기를 위한 별도의 스토리지 영역을 두는 것도 한 방법입니다.

1. 읽기 중심의 시스템

읽기 중심의 시스템에서는 데이터베이스 조회(Read) 작업이 대부분을 차지합니다. 이러한 시스템의 특징과 최적화 전략은 다음과 같습니다:

  • 읽기 전용 복제본 (Read Replicas): 읽기 요청이 많은 경우, 주 데이터베이스의 부하를 줄이기 위해 읽기 전용 복제본을 사용할 수 있습니다. 이 복제본은 주 데이터베이스와 동기화되어 데이터의 일관성을 유지하면서, 모든 읽기 쿼리를 처리할 수 있습니다. 이 방법은 데이터베이스의 읽기 처리량을 크게 향상시킬 수 있습니다.
  • 캐싱 (Caching): 자주 접근하는 데이터를 메모리 내 캐시에 저장하여, 데이터베이스 서버까지의 요청을 줄입니다. Redis, Memcached와 같은 인메모리 데이터 스토어를 사용하여 읽기 성능을 향상시킬 수 있습니다. 캐싱은 응답 시간을 단축하고, 데이터베이스의 부하를 줄이는 효과적인 방법입니다.
  • 쿼리 최적화: 쿼리의 효율성을 높여 읽기 성능을 개선할 수 있습니다. 실행 계획을 분석하고, 필요한 인덱스를 추가하여 데이터베이스 엔진이 데이터를 더 빠르게 검색할 수 있도록 합니다.

2. 쓰기 중심의 시스템

쓰기 작업이 상대적으로 많은 시스템에서는 다음과 같은 전략을 고려할 수 있습니다:

  • 로그 구조 병합 트리 (LSM-Tree): 이 데이터 구조는 쓰기 작업을 최적화하기 위해 설계되었습니다. LSM-Tree는 쓰기 작업을 메모리 내에서 빠르게 수행한 다음, 주기적으로 디스크에 일괄 쓰기를 수행합니다. 이는 쓰기 지연을 최소화하고, 높은 쓰기 처리량을 제공합니다. Cassandra와 LevelDB가 이 구조를 사용합니다.
  • 일괄 처리 (Batch Processing): 쓰기 작업을 일괄적으로 처리함으로써, 네트워크와 디스크 I/O를 줄이고 전체적인 시스템 성능을 향상시킬 수 있습니다. 데이터를 그룹화하여 한 번에 처리함으로써 자원 사용을 최적화합니다.
  • 별도의 쓰기 스토리지 영역: 쓰기 작업을 위해 특별히 최적화된 스토리지 영역을 구성할 수 있습니다. 예를 들어, SSD를 사용하여 빠른 쓰기 속도를 지원하고, 데이터베이스의 쓰기 성능을 개선할 수 있습니다.

<5> 속도 vs 정확도

  • tradeoff 관계이기때문에 우선순위를 선정해야함.
  • 금융 금액의 경우 1원이라도 틀려서는 안되나, 게시글의 조회수의 경우에는 1정도는 틀려도 괜찮음
  • 속도와 정확도 사이에서의 선택은 애플리케이션의 요구 사항과 사용자의 기대치를 바탕으로 결정됩니다. 금융 데이터의 경우, 오류나 불일치가 심각한 결과를 초래할 수 있기 때문에 ACID 원칙이 필수적입니다. 반면, 소셜 미디어와 같은 대규모 사용자 기반의 서비스에서는 빠른 응답 시간과 시스템의 높은 가용성이 더 중요할 수 있어 이벤추얼 일관성이 적합할 수 있습니다.
  • 트랜잭션 관리: ACID(원자성, 일관성, 고립성, 지속성) 원칙을 확실히 지키면서도 성능을 유지할 수 있는 트랜잭션 관리 전략을 구현합니다. 예를 들어, 은행 시스템에서는 강한 일관성이 필요하지만, 소셜 네트워크에서는 최종 일관성이나 이벤추얼 일관성(eventual consistency)을 허용할 수 있습니다.
  • 이벤추얼 일관성 (Eventual Consistency) : 이벤추얼 일관성은 분산 데이터베이스 시스템에서 널리 사용되는 일관성 모델입니다. 모든 노드가 결국 최종적으로 일관된 상태에 도달한다는 것을 보장하지만, 트랜잭션이 완료된 직후에는 일부 노드가 최신 상태를 반영하지 않을 수 있습니다. 이 모델은 다음과 같은 특징을 가집니다:
    • 성능 최적화: 데이터의 즉각적인 일관성을 요구하지 않기 때문에, 응답 시간과 처리량이 향상됩니다.
    • 가용성 강화: 시스템의 일부가 실패해도 나머지 시스템이 계속 작동할 수 있습니다.
    • 적용 사례: 소셜 네트워크의 타임라인 업데이트, 온라인 상점의 재고 관리 등이 이벤추얼 일관성을 적용할 수 있는 예입니다.

적용 사례와 선택 기준

  • 금융 시스템: 은행 거래와 같이 정확성이 매우 중요한 시스템에서는 ACID 원칙을 엄격하게 적용합니다. 데이터의 정확성과 일관성이 시스템의 신뢰성을 결정짓기 때문입니다.
  • 소셜 미디어: 게시글 조회수나 댓글 같은 기능에서는 높은 가용성과 빠른 응답 시간이 중요합니다. 이 경우, 이벤추얼 일관성을 적용하여 사용자 경험을 향상시킬 수 있습니다.

 

 

 

<6>. READ 연산시 어떤 컬럼을 기준으로 읽어오는 지(인덱스 설계)

  • 회사의 코드를 기준으로 레코드를 읽는지, 회사의 이름을 기준으로 데이터를 읽어오는
  • 인덱스 설계: 주로 조회하는 컬럼에 인덱스를 구축하여 조회 성능을 향상시킵니다. 다만, 인덱스가 많을수록 쓰기 성능은 저하될 수 있으므로, 인덱스는 신중하게 선택해야 합니다.

인덱스 설계의 중요성

인덱스는 테이블의 특정 컬럼에 대한 포인터 목록을 유지하여 데이터베이스가 특정 값을 빠르게 찾을 수 있도록 돕습니다. 그러나 모든 컬럼에 인덱스를 설정하는 것은 비효율적일 수 있으므로, 주로 조회하는 컬럼에 대해 신중하게 인덱스를 구축해야 합니다.

인덱스 설계 시 고려할 요소

  1. 쿼리 패턴 분석:
    • 어떤 컬럼이 WHERE 절이나 JOIN, ORDER BY 절에서 자주 사용되는지 분석합니다. 이 컬럼들은 인덱스 후보가 될 수 있습니다.
  2. 선택도(Selectivity):
    • 선택도가 높은 컬럼, 즉 고유값의 비율이 높은 컬럼은 인덱스 효율이 좋습니다. 예를 들어, 회사 코드와 같은 고유 식별자는 인덱스에 좋은 후보입니다.
  3. 데이터 형태와 크기:
    • 데이터 유형(문자열, 숫자 등)과 크기도 인덱스 설계에 영향을 미칩니다. 예를 들어, 긴 텍스트보다는 짧은 코드나 숫자에 인덱스를 사용하는 것이 더 효율적입니다.
  4. 읽기와 쓰기의 비율:
    • 데이터베이스에 읽기 작업이 지배적이면 인덱스를 많이 사용할 수 있지만, 쓰기 작업이 많은 경우 인덱스를 과도하게 사용하면 성능 저하를 초래할 수 있습니다.

예시: 회사 데이터베이스 인덱스 설계

  • 회사 코드로 검색: 대부분의 조회가 회사 코드로 이루어진다면, 회사 코드 컬럼에 인덱스를 설정하여 조회 성능을 크게 향상시킬 수 있습니다. 회사 코드는 고유 식별자일 가능성이 높아 인덱스로 사용하기 적합합니다.
  • 회사 이름으로 검색: 회사 이름으로 자주 조회를 한다면, 회사 이름 컬럼에도 인덱스를 고려할 수 있습니다. 하지만 이름은 중복될 수 있고 선택도가 낮을 수 있어 인덱스의 효율이 다소 떨어질 수 있습니다. 이 경우, 전문 검색 인덱스(Full-Text Index)를 사용하는 것도 한 방법입니다.

인덱스 관리 전략

  • 인덱스 정기 리뷰: 데이터와 쿼리 패턴의 변화에 따라 인덱스의 효율성을 주기적으로 검토하고 필요에 따라 인덱스를 추가하거나 제거합니다.
  • 성능 모니터링: 인덱스의 영향을 모니터링하여, 성능 문제를 일으키는 인덱스를 식별하고 최적화합니다.

적절한 인덱스 설계는 데이터베이스 성능을 결정짓는 중요한 요소입니다. 따라서 신중한 분석과 지속적인 관리가 필요합니다.

 

<7>. 키는 어떻게 생성 해줄건지

  • 단순히 auto increment 혹은 다른 방식으로 설계할 것인지
  • 키 생성 전략: 자동 증가 키, UUID, 복합 키 등 다양한 키 생성 전략 중에서 시스템의 요구사항과 성능 목표에 맞는 전략을 선택합니다.

1. 자동 증가 키 (Auto-Increment Key)

  • 정의: 데이터가 삽입될 때마다 데이터베이스 관리 시스템(DBMS)이 자동으로 숫자를 증가시켜 키를 생성합니다.
  • 장점: 구현이 간단하고, 쉽게 예측할 수 있어 데이터 삽입 속도가 빠릅니다.
  • 단점: 분산 시스템에서는 충돌의 위험이 있어 규모 확장성이 제한적일 수 있습니다.
    • 분산시스템은 여러대의 서버를 사용하여 데이터를 저장하는 방식으로 각 서버마다 autoincrment를 적용할 시에 충돌이 있을 수 있음.
  • 적용: 단일 데이터베이스 서버에서 안정적으로 사용할 수 있으며, 트랜잭션이 빈번하고 작은 시스템에 적합합니다.

2. UUID (Universally Unique Identifier)

  • 정의: 알고리즘에 기반하여 고유성을 보장하는 128비트 길이의 식별자를 생성합니다.
  • 장점: 전 세계 어디서든 유니크한 값을 생성할 수 있어 분산 시스템에서 충돌 없이 사용할 수 있습니다.
  • 단점: 크기가 크고, 순차적이지 않아 인덱스 성능에 부정적인 영향을 미칠 수 있습니다.
  • 적용: 분산 데이터베이스, 클라우드 기반 시스템, 다중 서버 환경에서 유용합니다.

3. 복합 키 (Composite Key)

  • 정의: 두 개 이상의 컬럼을 결합하여 키를 생성합니다.
  • 장점: 데이터의 고유성을 더 세밀하게 관리할 수 있으며, 비즈니스 로직에 밀접하게 키를 설계할 수 있습니다.
  • 단점: 복잡한 쿼리와 더 많은 공간을 필요로 할 수 있으며, 관리가 복잡해질 수 있습니다.
  • 적용: 자연 키가 명확하지 않거나 여러 속성에 의해 데이터가 고유해질 경우 유용합니다.

4. 시퀀스와 트리거 (Sequences and Triggers)

  • 정의: 특정 규칙에 따라 숫자를 생성하거나, 특정 데이터베이스 이벤트에 반응하여 키를 자동으로 생성합니다.
  • 장점: 자동 증가 키보다 더 유연하게 키 값을 관리할 수 있습니다.
  • 단점: 설정과 관리가 복잡할 수 있습니다.
  • 적용: 특정 패턴이나 비즈니스 규칙에 따라 키를 생성해야 할 때 적합합니다.

선택 기준

키 생성 전략을 선택할 때는 다음과 같은 요소를 고려해야 합니다:

  • 데이터베이스 환경: 단일 서버인지, 분산 환경인지
  • 성능 요구사항: 삽입 성능, 조회 성능
  • 관리 용이성: 키 관리의 복잡성
  • 확장성 요구사항: 시스템의 확장 가능성
  • 비즈니스 요구사항: 데이터의 고유성과 무결성 요구사항

적절한 키 생성 전략을 선택하는 것은 데이터베이스의 효율성과 확장성을 크게 향상시킬 수 있으므로, 주어진 시스템과 요구사항에 맞는 방법을 신중히 고려하는 것이 중요합니다.

 

<8>.예상 트래픽은 어느 정도인지

 

  • 예상 트래픽 분석: 피크 시간과 비피크 시간의 트래픽을 분석하여, 트래픽이 몰리는 시간에 대비한 로드 밸런싱과 리소스 할당 전략을 수립합니다.

예상 트래픽 분석의 중요성

  • 성능 최적화: 피크 시간 동안의 과부하를 방지하고, 비피크 시간에는 리소스를 절약하여 전체적인 시스템 성능을 최적화합니다.
  • 비용 효율성: 클라우드 환경에서 리소스 사용을 최적화함으로써 비용을 절감할 수 있습니다.
  • 사용자 경험 개선: 시스템의 응답 시간을 단축하고, 사용자 경험을 향상시킬 수 있습니다.

트래픽 예측 및 분석 방법

  1. 데이터 수집:
    • 사용자의 접근 로그, 애플리케이션의 요청 로그, 서버의 성능 지표 등을 수집합니다.
  2. 패턴 분석:
    • 일별, 주별, 월별 트래픽 데이터를 분석하여 트래픽 패턴을 파악합니다.
    • 특별한 이벤트나 행사, 마케팅 캠페인 등이 트래픽에 미치는 영향을 분석합니다.
  3. 피크 타임 예측:
    • 피크 시간대를 예측하여, 이 시간에 발생할 수 있는 최대 트래픽 양을 추정합니다.
    • 시즌별 변동성과 트렌드를 고려하여 피크 타임을 정확히 예측합니다.

대응 전략

  1. 로드 밸런싱:
    • 로드 밸런서를 사용하여 여러 서버에 요청을 균등하게 분산시킵니다.
    • 지리적 로드 밸런싱을 구현하여 전 세계 사용자에게 근접한 데이터 센터에서 서비스를 제공할 수 있도록 합니다.
  2. 자동 스케일링:
    • 클라우드 기반 인프라를 활용하여 트래픽 변동에 따라 자동으로 서버 인스턴스의 수를 조절합니다.
    • 리소스 사용을 모니터링하고, 필요에 따라 자동으로 스케일 업(리소스 증가) 또는 스케일 다운(리소스 감소)을 수행합니다.
  3. 리소스 할당:
    • 피크 타임에 필요한 리소스를 미리 할당하고, 비피크 시간에는 할당된 리소스를 줄여 비용을 절감합니다.
    • CPU, 메모리, 네트워크 대역폭 등의 리소스를 적절히 조절합니다.

모니터링 및 조정

  • 성능 모니터링 도구를 사용하여 실시간으로 트래픽과 서버 성능을 모니터링합니다.
  • 트래픽 패턴이나 시스템 성능에 변화가 있을 경우, 로드 밸런싱 설정과 리소스 할당을 조정합니다.

적절한 예상 트래픽 분석과 이에 기반한 로드 밸런싱 및 리소스 할당 전략은 데이터베이스와 전체 시스템의 안정성과 효율성을 크게 향상시킬 수 있습니다. 이러한 전략은 기술적 실행 뿐만 아니라 비즈니스 성공에도 중요한 역할을 합니다.

 

데이터베이스 인프라 구조

<9>.데이터 베이스의 파티션은 어떻게 구성할 건지

  • 데이터베이스 파티셔닝: 데이터를 여러 파티션으로 나누어 관리함으로써 관리의 복잡성을 줄이고, 성능을 최적화합니다. 데이터의 접근 패턴에 따라 수평적 또는 수직적 파티셔닝을 적용할 수 있습니다.

수평 파티셔닝 (Horizontal Partitioning)

수평 파티셔닝은 테이블의 행을 기준으로 데이터를 여러 파티션으로 나누는 방식입니다. 각 파티션은 동일한 스키마를 가지지만, 다른 데이터 서브셋을 포함합니다.

장점:

  • 로드 밸런싱: 데이터를 여러 서버에 분산시켜 처리할 수 있어, 로드 밸런싱과 고가용성을 실현할 수 있습니다.
  • 성능 향상: 쿼리 성능이 향상될 수 있으며, 특히 대량의 데이터에 대한 검색, 삽입, 업데이트가 더 빨라집니다.
  • 관리 용이성: 각 파티션은 독립적으로 백업하고 복구할 수 있어 데이터 관리가 용이해집니다.

사용 사례:

  • 시간 기반 파티셔닝: 로그 데이터나 이벤트 데이터와 같이 시간에 따라 빠르게 증가하는 데이터에 적합합니다.
  • 지역 기반 파티셔닝: 사용자의 지리적 위치에 따라 데이터를 분할하여, 지역별로 데이터를 관리하고 접근 속도를 향상시킬 수 있습니다.

수직 파티셔닝 (Vertical Partitioning)

수직 파티셔닝은 테이블의 열을 기준으로 데이터를 분할하는 방식입니다. 이는 테이블을 여러 서브테이블로 나누어 각각이 서로 다른 컬럼 집합을 가지게 됩니다.

장점:

  • 성능 최적화: 자주 접근하는 컬럼을 분리하여 성능을 향상시킬 수 있습니다.
  • 입출력 감소: 관련 없는 데이터의 입출력을 줄임으로써 전체적인 시스템 부하를 감소시킬 수 있습니다.

사용 사례:

  • 특정 열에 빈번한 접근: 특정 열이 다른 열에 비해 자주 사용되는 경우, 이러한 열을 별도로 분리하여 빠른 데이터 액세스를 제공합니다.
  • 보안 강화: 민감한 데이터를 분리하여 보안을 강화할 수 있습니다.

파티셔닝 전략 선택 기준

  • 데이터의 접근 패턴: 어떤 열이나 행이 자주 접근되는지를 분석합니다.
  • 데이터의 크기와 성장 예측: 데이터의 현재 크기와 미래 성장을 고려해야 합니다.
  • 트랜잭션의 특성: 트랜잭션이 데이터에 미치는 영향과 요구되는 성능을 고려합니다.

적절한 파티셔닝 전략은 데이터베이스의 성능을 극대화하고, 데이터 관리를 효율적으로 만들어 줄 수 있습니다. 각 조직의 특정 요구사항에 맞춰서 가장 적합한 파티셔닝 방식을 선택하는 것이 중요합니다.

 

위의 질문에 따라서 어떤 데이터베이스를 써야하는지부터 생각할 수 있음.