[QueryDsl] 성능 개선(exists, 다중 조건)

Simple·2022년 8월 7일
0

JPA

목록 보기
5/6

1. exists

querydsl 에서 exists문을 사용하려면

@Override
public boolean exists(Predicate predicate) {
    return createQuery(predicate).fetchCount() > 0;
}

이렇게 fetchCount를 사용해야하는데 여기에 치명적인 단점이 있다.

exists는 데이터 1개만 찾고 결과를 리턴하는 반면
count는 모든 데이터를 조회하기 때문에 데이터가 많아질수록 성능 차이가 난다.

우리의 목적은 데이터 1개만 찾는 것이기 때문에
이것을 보완하는 방법은 fetchFirst를 사용하는 것이다.

public boolean existUser(Long userId){
	Integer fetchFirst = queryFactory
    		.selectOne()
            .from(user)
            .where(user.id.eq(userId))
            .fetchFirst();
            
    return fetchFirst != null;

주의: 데이터가 없으면 null을 반환한다.

2. 다중 조건

만약 관리자가 회원을 조회한다면 조건으로 이름으로도 할 수 있고, 유저 아이디로도 할 수 있고, 가입 날짜로도 할 수 있고, 회원 상태로도 할 수 있는 선택지들이 있을 것이다.

  • 이름: where name = name
  • 유저 아이디: where username = username
  • 가입 날짜: where joinedDate = joinedDate
  • 회원 상태: where status = status

중요한 점은 어떤 조건으로 검색할지 모른다는 상황이다.

그럴 때 queryDsl에서 제공하는 기능이 BooleanExpression이다.

public List<User> findAllByUsers(String name, String username, String joinedDate, Status status, int pageIndex, int pageSize){
        return queryFactory
                .selectFrom(user)
                .where(user.authority.eq(Authority.ROLE_USER),
                        eqName(name),
                        eqUsername(username),
                        eqCreatedAt(joinedDate),
                        eqStatus(status))
                .orderBy(user.createdAt.desc())
                .offset(pageIndex * pageSize)
                .limit(pageSize)
                .fetch();
}

private BooleanExpression eqName(String name){
        if(!StringUtils.hasText(name))  return null;
        return user.name.eq(name);
}

private BooleanExpression eqUsername(String username){
        if(!StringUtils.hasText(username))  return null;
        return user.username.eq(username);
}

private BooleanExpression eqCreatedAt(String joinedDate) {
        if (!StringUtils.hasText(joinedDate)) return null;
        else {
            LocalDate date = LocalDate.parse(joinedDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            return user.createdAt.between(date.atStartOfDay(), LocalDateTime.of(date, LocalTime.MAX));

        }
}
private BooleanExpression eqStatus(Status status){
        if(status==null)    return null;
        else if(!StringUtils.hasText(status.toString())) return null;
        return user.status.eq(status);
}

이렇게 각 메서드를 통해 조건에 맞으면 조건문을, 맞지 않으면 null을 반환함으로써 다양한 상황에 대비하여 동적 쿼리를 생성할 수 있다.

profile
몰입하는 개발자

0개의 댓글