서버구축 - 데이터베이스 기본

anvel·2025년 8월 2일

항해 플러스

목록 보기
33/39

항해 플러스 백엔드 - 데이터베이스 기본

서버구축 - 데이터베이스 기본

이번 주차는 기존 DB설계로 적절한 index를 지정하여 쿼리의 병목현상이나 특정 기능에 대한 조회 개선을 목표로 하는 과정이었습니다.

정규화와 반정규화

기본적으로 DB는 중복을 없애고, 동일한 정보를 갖는 데이터의 정합성을 보장해야합니다.
하지만, 비즈니스적으로 요구사항에 따라, 혹은 조회의 성능이 중요한 경우에는 반정규화를 통해 조인 조건을 줄이는 방향으로 중복을 허용할 수 있습니다.

  • 정규화: 중복 제거, 데이터 정합성 ↑ → 쓰기 성능 우선
  • 반정규화: 조인 최소화, 단일 조회 성능 ↑ → 읽기 성능 우선

인덱스 설계와 성능 튜닝

인덱스 설계 전략은 단일/복합 인덱스로, 조합 조건, 정렬, 그룹핑을 고려하여 카디널리티가 높은 칼럼을 지정합니다.

EXPLAIN을 통해 쿼리를 실행 계획을 확인하고, type=ALL, key=NULL, Using filesort, Using temporary 등 병목을 탐지하여 인덱스를 지정하고, 쿼리의 조건을 조정합니다.

적용안 개선점 및 실행 계획

테이블 구조 개선안

  • 식별자 기반 연관 관계에서 객체 기반 참조 방식으로 수정
    • @ManyToOne, @OneToMany, @JoinColumn 활용한 FK 연결 생성, 양방향 참조하도록 변경했습니다.
    • 칼럼 중에 OrderItem에 대한 역정규화를 적용했습니다.
    • OrderItem.orderedAtnullable로 지정하여 Order 생성을 위한 객체 상태일 때는 null이고,
    • Order의 생성자에서 OrderItem.orderedAt 반정규화 필드를 동기화하도록 작성했습니다.
  • 도메인 별 index 추가
    • MySQL InnoDB 기반에서 FK 지정 시 index가 생성되어 별도의 외래키를 위한 index는 만들지 않았습니다.
    • 확장성을 고려해서, 비즈니스를 위한 목적의 index를 추가했습니다.
    • 상품 이름 검색 , 사용자 이름 검색 등 검색이나, 주문의 상태, 잔액의 사용/충전 타입과 같은 필터링 목적의 index를 지정했습니다.
    • 다만, 이름 검색의 경우에는 완전 일치나 OOO% 방식의 와일드카드만 성능에 영향이 있을 것으로 판단됩니다.
    • 사용자별 쿠폰 사용여부, 사용자별 쿠폰 중복 발급 여부과 같은 비즈니스 로직을 위한 복합인덱스를 구성했습니다.

실행 계획

이부분은 실행계획을 작성해보는 경험을 하는 것을 과제를 진행했습니다.
실제로 index에 대한 개선된 부분을 도출하는 것에는 실패했습니다.

  • 작성한 실행 계획 조건
    • 방법 1: Order.orderedAt 필터 + 조인
    • 방법 2: OrderItem.orderedAt 단독 필터
    • 방법 3-1: 복합 인덱스 (orderedAt, productId)
    • 방법 3-2: 복합 인덱스 (productId, orderedAt)

피드백

  • 실행계획이나 인덱스의 카디널리티에 대한 개념이 아직 부족했습니다.
  • 복합인덱스나 단일 인덱스나 orderedAt을 Datetime으로 지정했을 때, 인덱스를 저장하는 효율이 나오지 않기 때문에 오히려 테이블의 불필요한 사이즈만 커지는 경우가 되는 것을 그대로 작성하여 성능에 도움이 되지 않는 결과가 되었습니다.

마치며

  • Java, SQL을 너무 몰랐다는 생각이 커지는 계기가 되었습니다.
  • 한번 놓치니 학습 시간이 많이 부족해지는 한 주였습니다. 이번주로 인해 다음주도 추가 조치를 하느라 밀리지 않았으면 좋겠으나, 마음처럼 안될 것 같습니다.

0개의 댓글