Client 테이블과 Bundle 테이블은 1:N 관계이다.
Client 테이블에서 Bundle 테이블의 PK를 외래키로 가지고 있는 것이다.
Client(clinet_id(PK), ... , bundle_id(FK))
Bundle(bundle_id, ...)
클래스는 다음과 같이 만들어져있다.
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Client extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "client_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "bundle_id")
private Bundle bundle;
...
}
@Entity
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Bundle extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "bundle_id")
private Long id;
...
}
해당 상황에서 Client_ID
와 Bundle_Id
필드들의 값이 주어졌을 때
Client
테이블에 해당 데이터가 테이블에 있는지 확인해야 한다.
다음 JpaRepository에서 기본적으로 제공해주는 쿼리 메소드를 사용해서 쿼리를 날려보겠다.
public interface ClientRepository extends JpaRepository<Client, Long> {
boolean existsByIdAndBundle_Id(Long clientId, Long bundleId);
}
다음과 같이 left outer join
을 써서 조회해오고 있다.
하지만 나는 Client
테이블 내에서 조인없이 해결하길 원한다. 다른 테이블을 매칭시켜야 하기 때문에 조인이 껴버리면 성능이 떨어질 수 밖에 없다.
QueryDSL을 이용해서 exists 메소드를 직접 구현해보자.
JpaRepository에서 제공하는 exists 메소드도 결국 select로 id를 가져와서 값이 있으면 true를 반환하도록 되어있다. 또한 limit로 최적화를 하고 있다.
JpaRepository와 똑같이 구현해주고, 조인만 없애면 된다.
@Autowired
JPAQueryFactory query; // QueryDSL 관련 설정이 있어야 함.
private boolean find(long bundleId, long clientId) {
// exists 메서드 구현
Integer exists = query.selectOne()
.from(client)
.where(client.id.eq(clientId), client.bundle.id.eq(bundleId))
.fetchFirst();
return exists != null;
}
이제 조인없이 조회해오는 것을 확인할 수 있다.