1. 수천만에서 수억개의 데이터 어떻게 처리하나?
1. extends/ implemnet 사용하지 않기
- JpaRepository 사용하지 않음 → 불편해
- entity 지정도 번거로움
- 자유롭게 Querydsl를 사용할 방법 찾기
- 결론: queryFactory만을 이용해서 Querydsl만 사용할 수 있도록 만든다.
2. 동적쿼리 사용하기
- if문을 이용하면 복잡해지고 가독성이 떨어짐
- BooleanExpression을 통해서 자동으로 조건절에서 제거
2. 성능개선- select
1. exist 메소드 금지
- count(1)>0으로 대체
- 발견하는 순간 끝나기 때문에 성능차이가 크다.
- limit 1로 조회를 제한
- 특이사항: null이냐 아니냐고 결과값이 나옴
2. Cross Join 회피
- cross join은 모든 가능성에 대한 것이여서 성능 저하가 생김
- 묵시적 join으로 cross join이 발생할 수 있음
- 최적화를 직접할 수 있다면 db에게 맡길필요 없다.
- Hibernate 이슈
- 해결: 명시적 join으로 cross를 막는다.
3. Entity보다 DTO를 우선으로 사용
- Entity 사용시 문제
- n+1 문제
- 불필요한 컬럼들도 조회됨
- 단순 조회 기능에서 성능 이슈 요소가 발생됨
- Entity 조회와 Dto 조회를 구분
- 고강도 성능 개선, 대량의 데이터 조회의 경우 Dto 사용
- 조회 컬럼을 최소화
- 이미 매개변수로 온 데이터는 as 표현식으로 대체함
- select 컬럼에 entity 자제
- oneToone은 lazy loading이 안된다. ⇒ 매건 마다 조회
3. Group By 최적화
- filesort가 반드시 작동해서 성능저하로 이어진다.
- sql에선 orderByNull로 넘어갈 수 있음
- JPA에서는 orderByNull이 없기 때문에 직접 구현해서 넣어준다.
- 정렬이 필요하더라도 조회결과가 100건 이하면, 애플리케이션에서 정렬해라
- 단, 페이징일 경우는 orderByNull 못쓴다.
- DB서버 보다는 WAS 서버가 훨씬 널널하기 때문에 자잘한건 애플리케이션에서 처리해도 좋음
4. 커버링 인덱스
: 쿼리 충족을 위한 모든 컬럼을 갖고 있는 인텍스
- select, where, order by, group by 등에서 사용되는 모든 컬럼이 인덱스에 포함됨
- 페이징 성능을 향상시키는 보편적인 방법
- 하지만, JPQL from 절의 서브쿼리 지원을 안 함
- JPQL에서의 우회법
- Cluster Key(PK)를 커버링 인덱스로 조회 → 조회된 key로 select 컬럼 후속 조회
3. Update 성능 향상
1. 일괄 Update 사용으로 최적화
- 직접 가져와서 하나씩 update하면 성능 저하가 커진다.
- 단점: hibernate 캐시는 일괄 업데이트 시에 업데이트가 안됨
- Dirty checkong: 실시간 비즈니스에 좋음
- Querydsl.update: 대량의 업데이트
결론: Entity와 DTO의 분리는 진짜 중요. (필요한 항목만 조회, 업데이트)
4. JPA Bulk Insert 자제
JPA에서는 JDB의 Insert 합치기 옵션이 적용되지 않는다.
- merge, persist 보다 batch 훨씬 성능이 좋다.
- jdbcTemplate로 처리 가능하지만, Type Safe가 어려움