언어, 프레임워크/Spring

대용량 데이터에서의 성능 최적화

go_getter 2025. 5. 19. 02:04

DB에서의 성능 최적화

1. 인덱스 적용

  • where, join, order by에 자주 사용되는 컬럼에 인덱스를 적용한다.
  • 인덱스가 너무 많으면 성능이 저하된다.
  • 고유한 값에 인덱스를 적용하는 것이 효율이 좋다.

> MySQL 기준 인덱스 적용하기

-- 단일 컬럼 인덱스
CREATE INDEX index_name ON table_name (column_name);

-- 다중 컬럼(복합 인덱스)
CREATE INDEX index_name ON table_name (column1, column2);

 

복합 인덱스의 경우 왼쪽부터 차례대로 사용되는 경우에만 활용되며 왼쪽 정렬 원칙(Left-most Prefix Rule) 이라고 부른다.

 

> JPA에서 인덱스 적용하기

@Entity
@Table(name = "users", indexes = {
    @Index(name = "idx_user_name", columnList = "name"), // 인덱스명 생략 가능
    @Index(name = "idx_user_name_age", columnList = "name, age")
})
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private Integer age;
}
@Column(unique = true) // unique 설정한 필드는 자동 인덱스 생성
private String email;
spring.jpa.hibernate.ddl-auto=create  # 또는 update

 

 

2. 정규화 ↔ 비정규화 판단

  • 조회 성능이 더 중요하다면 부분 비정규화 고려
  • ex. 조인 줄이기 위해 중복 데이터 허용
  • 데이터 무결성이 중요하면 정규화 유지

3. CQRS + Eventual Consistency

  • 쓰기 DB와 읽기 DB를 분리 → 확장성과 성능 개선
  • 이벤트 기반 비동기 동기화로 최신성 유지

4. Batch Insert / Update 처리

  • 대량 쓰기 작업 시, 루프보다 batch 처리로 성능 향상

5. Partitioning / Sharding

  • 테이블이 너무 커질 경우, 수평 파티셔닝 또는 DB 샤딩 적용

6. 데이터 보관 주기 및 이력 분리

  • 오래된 데이터는 히스토리 테이블로 분리하여 조회 성능 확보

 


서비스에서의 성능 최적화

1. 캐싱

  • 조회 빈도 높은 데이터는 Redis 등 인메모리 캐시로
  • 캐시 무효화 정책 설계 중요 (TTL, 수동 삭제 등)

2. 조회 쿼리 튜닝

  • N+1 문제 방지 (JPA fetch join, DTO projection, query DSL 등)
  • 페이징 처리 시 count() 최적화 고려

3. 비동기 처리 / 메시지 큐 활용

  • 처리 시간이 오래 걸리는 작업은 MQ 또는 비동기 처리
    • 예: Kafka, RabbitMQ

4. 서비스 로직 단순화

  • 복잡한 계산 로직은 별도 비동기 처리 또는 저장된 결과 사용

5. 지속적인 모니터링과 병목 분석

  • APM 도구(NewRelic, Pinpoint, Datadog 등) 사용해 병목 추적
  • 쿼리 슬로우 로그, GC 로그 분석 병행