728x90
반응형
source 는 Github 에 있습니다.
목차는 Querydsl 목차 에 있습니다.
[Querydsl 2편] querydsl 성능 관련 정리
Querydsl Tip
implement, extends
- implement, extends 를 사용해서 querydsl 사용하지 않는 것이 좋습니다.
- JpaQueryFactory 만 빈으로 선언해주면 implement, extends 를 사용하지 않아도 됩니다.
동적 쿼리 BooleanExpression
- 아래처럼 명시적으로 만드는게 좋습니다.
return queryFactory
.selectFrom(xxx)
.where(eqAge(age),
eqTel(tel))
.fetch();
private BooleanExpression eqAge(String age) {
xxxx
}
성능 (Select)
querydsl 에서 exist
- 보통 데이터가 얼마나 존재하는지 체크할 떄, exist 가 count 보다 성능이 잘나옵니다. (exist 가 빠른 이유는 조건에 해당하는 row 1개만 찾으면 종료하기에 빠름)
- querydsl exist 는 exist 를 사용하지 않고 count(1) 로 동작됩니다. (즉, 데이터를 전부 읽어들입니다.)
- querydsl 에서 exist 를 사용하고 싶을 시, 아래 예제와 같이 구현하면 됩니다.
@Transactional(readOnly = true)
public Boolean exist(Long id) {
String resultOne = queryFactory
.selectOne()
.from(test)
.where(test.id.eq(id))
.fetchFirst(); // limit 1
return resultOne != null; // 값이 없으면 null 반환
}
Querydsl 결과에 대해서 Entity 보다는 DTO 사용
- Entity 를 사용하면 보통 Entity 의 컬럼을 전부 사용하지 않습니다. (즉, 성능 낭비입니다.)
- Select 컬럼에는 Entity 자제하고, DTO 를 만들어서 필요한 컬럼만 조회하는 것이 성능에 좋습니다.
- One To One 같은게 있으면 N+1 이 발생, 또는 불필요한 컬럼까지 조회됩니다.
- distinct 를 사용할 경우 select 절에 Entity 가 있을 경우 전체에 대해 distinct 가 동작하기에 성능 낭비입니다.
Group by 최적화
- MySQL 에서 인덱스가 없는 컬럼에 대해 group by 를 하게 되면 filesort 가 발생합니다.
- group by 를 하는데 filesort 가 필요할 수도 있고 안할수도 있습니다. 안하는 경우 성능 낭비입니다.
- 이를 해결하기 위해서는 MySQL 에서 order by null 문법을 사용하면 Filesort 가 제거가 되는데 Querydsl 에서는 이를 지원하지 않습니다.
- querydsl 에서 직접 만들어서 처리하면 되며, 페이징일 경우 order by null 사용할 수 없습니다.
정렬
- 정렬이 필요할 경우 데이터가 적다면 DB 에서 order by 를 하는게 아니라 프로그램단에서 sort 하는게 좋습니다.
- application 레벨의 자원이 DB 보다는 보통 더 빵빵하기에 이 방법이 좋습니다.
커버링 인덱스
- select 한 데이터가 전부 인덱스에 존재할 경우 디스크를 접근안하기에 성능이 좋습니다. DB 성능 저하의 대부분은 디스크에 접근할 때 발생합니다.
- 페이징 조회 성능을 향상시키는 보편적인 방법은 커버링 인덱스를 사용하는 것이며, 예제는 아래와 같습니다.
- 아래 쿼리 동작방식을 보면 id 를 인덱스에서 (메모리) 조회해오기에 빠르게 조회해옵니다.
- 가져온 ID 를 가지고 자체 조인해서 가져오는 방식입니다.
- Querydsl 은 JPQL 을 만드는 오픈소스이고, JPQL 은 서브쿼리를 지원안합니다.
- 아래 처럼 id 를 먼저 조회해오고 다시 쿼리를 날려 id 로 조회하면 커버링 인덱스 방식으로 데이터를 조회합니다.
select *
from test t
join (select id
from test
order by id
limit 100, 10) as tmp // 이 부분이 페이징 부분이고.
on tmp.id = t.id
List<Long> ids = queryFactory.
xxx
xxx
.fetch();
return queryFactory
.select(xxx)
.where(test.id.in(ids)
;
성능 개선 (Update / Insert)
- dirty checking 을 통해 데이터를 업데이트하는건 단건이면 괜찮습니다. 그러나 dirty checking 을 통해 바꾸는 데이터가 많다면 update 쿼리를 한 번 호출해서 바꾸는게 훨씬 효율적입니다.
- 실시간 비즈니스 처리 ,단건 처리면 dirty checking 사용하는 것이 좋습니다.
- 대량 처리면 update 사용하는 것이 좋습니다.
Reference
'Jpa > querydsl' 카테고리의 다른 글
[Querydsl 3편] querydsl from 에 서브 쿼리 넣는 방법 (0) | 2022.04.25 |
---|---|
[Querydsl 1편] querydsl 상속, 구현 없이 환경 세팅 (0) | 2022.01.03 |
spring-batch QuerydslPagingItemReader 설명 (0) | 2021.04.14 |
Jpa querydsl selectFrom 간단한 예제 (0) | 2020.12.05 |
jpa querydsl group by 예제 설명 (0) | 2020.11.28 |
댓글