728x90
반응형
Question엔티티 구성은 아래와 같다.
@Getter
@Setter
@Entity
public class Question {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(length = 200)
private String subject;
@Column(columnDefinition = "TEXT")
private String content;
private LocalDateTime createDate;
@OneToMany(mappedBy = "question", cascade = CascadeType.REMOVE)
private List<Answer> answerList;
}
Question엔티티를 게시판 형태로 나온다.
게시판을 불러오기 위해서 N+1 문제가 발생된다.
아래 쿼리를 통해 살펴보자.
게시물 조회 Query
// 게시물을 불러오는 쿼리
SELECT q1_0.id,
q1_0.content,
q1_0.create_date,
q1_0.subject
FROM question q1_0
ORDER BY q1_0.create_date DESC LIMIT 290, 10;
페이징을 이용하기 위한 쿼리
// 페이징을 이용하기 위한 쿼리
SELECT COUNT(q1_0.id)
FROM question q1_0;
답변 개수 조회 쿼리
SELECT a1_0.question_id,
a1_0.id,
a1_0.content,
a1_0.create_date
FROM answer a1_0
WHERE a1_0.question_id = 10;
SELECT a1_0.question_id,
a1_0.id,
a1_0.content,
a1_0.create_date
FROM answer a1_0
WHERE a1_0.question_id = 9;
SELECT a1_0.question_id,
a1_0.id,
a1_0.content,
a1_0.create_date
FROM answer a1_0
WHERE a1_0.question_id = 8;
SELECT a1_0.question_id,
a1_0.id,
a1_0.content,
a1_0.create_date
FROM answer a1_0
WHERE a1_0.question_id = 7;
SELECT a1_0.question_id,
a1_0.id,
a1_0.content,
a1_0.create_date
FROM answer a1_0
WHERE a1_0.question_id = 6;
SELECT a1_0.question_id,
a1_0.id,
a1_0.content,
a1_0.create_date
FROM answer a1_0
WHERE a1_0.question_id = 5;
SELECT a1_0.question_id,
a1_0.id,
a1_0.content,
a1_0.create_date
FROM answer a1_0
WHERE a1_0.question_id = 4;
SELECT a1_0.question_id,
a1_0.id,
a1_0.content,
a1_0.create_date
FROM answer a1_0
WHERE a1_0.question_id = 3;
SELECT a1_0.question_id,
a1_0.id,
a1_0.content,
a1_0.create_date
FROM answer a1_0
WHERE a1_0.question_id = 2;
SELECT a1_0.question_id,
a1_0.id,
a1_0.content,
a1_0.create_date
FROM answer a1_0
WHERE a1_0.question_id = 1;
해결방안
답변 개수를 조회하는 쿼리가 10개 실행된것을 볼 수 있는 이는 비효율적인것을 볼 수 있다.
만약 한 페이지에 질문 게시글이 100개씩 보여준다고 하면 100개의 쿼리가 실행된다는 것이다.
이러한 문제를 해결하기 위해서 default_batch_fetch_size를 설정해줘야한다.
BatchSize 설정
spring.jpa.properties.hibernate.default_batch_fetch_size=1000 // 1000개로 설정
default_batch_fetch_size는 복잡한 조회 쿼리를 IN절을 이용해서 한꺼번에 처리할 수 있다. 성능 개선에 유용하다.
default_batch_fetch_size를 이용한 답변 개수 조회 쿼리
SELECT a1_0.question_id,
a1_0.id,
a1_0.content,
a1_0.create_date
FROM answer a1_0
WHERE a1_0.question_id IN (10, 9, 8, 7, 6, 5, 4, 3, 2, 1);
결과는 똑같지만 쿼리 개수가 줄어들어서 더 효율적이다. 이는 데이터가 많은 경우에 유리하다.
만약 배치사이즈를 5로 설정하게 되면 아래와 같이 5 5 나눠서 2개의 쿼리가 실행된다.
SELECT a1_0.question_id,
a1_0.id,
a1_0.content,
a1_0.create_date
FROM answer a1_0
WHERE a1_0.question_id IN (10, 9, 8, 7, 6);
SELECT a1_0.question_id,
a1_0.id,
a1_0.content,
a1_0.create_date
FROM answer a1_0
WHERE a1_0.question_id IN (5, 4, 3, 2, 1);
하지만 여기서 드는 의문은 사이즈를 엄청 큰 숫자로 해서 하면 좋을텐데 왜 배치사이즈를 1000개로 한정을 했는지 라는 생각을 하게 된다.
객체 1000개가 메모리에 올라가는 거니까 램을 사용한다는건데 배치사이즈를 1조개로 설정하면 1조개의 객체가 메모리에 한꺼번에 올라가면 느려지거나 작동이 안될수 있기때문이다.
그래서 보통 배치사이즈는 1000개로 설정한다.
728x90
반응형
'Spring Framework' 카테고리의 다른 글
[Spring Framework] LazyCollectionOption.EXTRA 으로 SQL 최적화 (0) | 2023.03.30 |
---|---|
[Spring Framework] 엔티티 객체 등록날짜/수정날짜 자동화 (0) | 2023.03.20 |
[Spring Boot] DB 연결하기 (0) | 2023.03.20 |
[Spring Boot] @Autowired와 @Component의 관계 (0) | 2023.03.20 |
[Spring Boot] 인텔리제이에서 Spring Boot 자동 빌드 설정 (0) | 2023.03.18 |