티스토리 뷰
이번에 작성할 글은 query dsl 을 사용하여 fetch join 을 사용할시에 limit 를 사용할시 주의하여야 할 점에 대하여 정리하고자 합니다!
블로그 코드는 GitHub 에서 볼 수 있습니다
최초 데이터
USER TABLE (ONE) 3개의 데이터 존재
INSERT INTO USER (idx, user_id, password, name, email) VALUES (1, 'joonghyun', 'pwd1', '최중현', 'wndgus@gmail.com');
INSERT INTO USER (idx, user_id, password, name, email) VALUES (2, 'dakim', 'pwd2', '김다애', 'ekdo@gmail.com');
INSERT INTO USER (idx, user_id, password, name, email) VALUES (3, 'jangsi', 'pwd3', '장시후', 'tlgn@gmail.com');
ARTICLE TABLE (MANY) 8개의 데이터 존재
INSERT INTO ARTICLE (idx, user_idx, content, category) VALUES(1, 1, '내용1', '01');
INSERT INTO ARTICLE (idx, user_idx, content, category) VALUES(2, 1, '내용2', '01');
INSERT INTO ARTICLE (idx, user_idx, content, category) VALUES(3, 1, '내용3', '01');
INSERT INTO ARTICLE (idx, user_idx, content, category) VALUES(4, 1, '내용4', '01');
INSERT INTO ARTICLE (idx, user_idx, content, category) VALUES(5, 2, '내용5', '01');
INSERT INTO ARTICLE (idx, user_idx, content, category) VALUES(6, 2, '내용6', '01');
INSERT INTO ARTICLE (idx, user_idx, content, category) VALUES(7, 3, '내용7', '02');
INSERT INTO ARTICLE (idx, user_idx, content, category) VALUES(8, 3, '내용88', '02');
위 2개의 TABLE 을 가지고 LEFT JOIN 쿼리문은 보통 이렇게 작성하실 겁니다.
SELECT * FROM USER A LEFT JOIN ARTICLE B ON A.idx = B.user_idx LIMIT 2;
@Override
public List<User> findWithArticle_not_fetch_join() {
return this.queryFactory.selectFrom(user)
.leftJoin(user.articles, article)
.limit(2)
.fetch();
}
- 실행되는 query dsl 쿼리 실행문 -
select
user0_.idx as idx1_3_,
user0_.email as email2_3_,
user0_.name as name3_3_,
user0_.password as password4_3_,
user0_.user_id as user_id5_3_
from
user user0_
left outer join
article articles1_
on user0_.idx=articles1_.user_idx limit ?
여기에서 나오는 결과는 아래와 같습니다.
하지만 여기에서 fetch join 을 사용하면 어떻게 되는지 보겠습니다.
@Override
public List<User> findWithArticle_fetch_join() {
return this.queryFactory.selectFrom(user)
.leftJoin(user.articles, article)
.fetchJoin()
.limit(2)
.fetch();
}
위와 동일한 query dsl 문이며 left join 밑에 fetch join 이 추가 되었습니다.
- 실행되는 query dsl 쿼리 실행문 -
select
user0_.idx as idx1_3_0_,
articles1_.idx as idx1_0_1_,
user0_.email as email2_3_0_,
user0_.name as name3_3_0_,
user0_.password as password4_3_0_,
user0_.user_id as user_id5_3_0_,
articles1_.category as category2_0_1_,
articles1_.content as content3_0_1_,
articles1_.user_idx as user_idx4_0_1_,
articles1_.user_idx as user_idx4_0_0__,
articles1_.idx as idx1_0_0__
from
user user0_
left outer join
article articles1_
on user0_.idx=articles1_.user_idx LIMIT 가 존재하지 않습니다 ! 즉 모든 데이터를 풀스캔하여 조회 하게 됩니다. 주의..!!
즉 one to many 관계 에서 fetch join 후 limit 를 사용하게 되면 모든 데이터를 one to many 관계에 맞추어 fetch 가 이루어지고 난 후에 2개의 one (USER TABLE) 의 값을 리턴해 줍니다.
아래는 결과 입니다.
2개의 USER 도메인에 ARTICLE LIST 가 모두 fetch 되었으며 그 후에 2개의 USER 도메인만 리턴 됩니다.
결론
fetch join 시 LIMIT 를 사용할때에는 query dsl 에서 모든 데이터를 조회후 LIMIT 에 맞추어 잘라주고 있습니다. 이를 꼭 확인하여야 합니다..!
WHERE절이 존재할경우 WHERE 절에 맞추어 데이터가 먼저 추출되고 그후에 추출된 데이터 기반으로 fetch join 이 이루어지고 그후에 LIMIT 에 맞추어 데이터를 리턴합니다.
처음에는.. fetch join 시 n+1 문제를 해결해 준다고 아무생각 없이 여기저기에 붙여서 사용하였습니다.. 항상 생성되는 쿼리를 확인하고 쿼리플랜을 확인해가며 개발을 하여야 할 것 같습니다.!
- Total
- Today
- Yesterday
- 페치조인
- fetch join
- JUnit
- gradle
- query dsl
- Limit
- @Valid
- Jenkins
- query
- ec2
- error
- Validation
- Spring Boot
- SpringBoot
- fetchjoin
- hibernate
- 개발
- spring
- DEMONIZE
- insert
- QueryDSL
- Docker
- jpa
- spring-data-jpa
- web
- Database
- n+1
- orm
- SonarQube
- 쿼리
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |