๊ด€๋ฆฌ ๋ฉ”๋‰ด

Tech Log ๐Ÿ› ๏ธ

[jpa] ์ปฌ๋ ‰์…˜ ์กฐํšŒ ์ตœ์ ํ™” - 1 ๋ณธ๋ฌธ

jpa

[jpa] ์ปฌ๋ ‰์…˜ ์กฐํšŒ ์ตœ์ ํ™” - 1

sehaan 2023. 2. 27. 22:26

์ผ๋Œ€๋‹ค ๊ด€๊ณ„์ธ ์ปฌ๋ ‰์…˜์„ ํŽ˜์น˜ ์กฐ์ธ์œผ๋กœ ์กฐํšŒํ•  ๋•Œ,

ํ•˜๋‚˜์˜ ์ •๋ณด์— ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ปฌ๋ ‰์…˜์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ๊ฐ€ ๋Š˜์–ด๋‚˜๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์ ํ™”์— ์–ด๋ ค์›€์ด ์žˆ๋‹ค.

 

๋•Œ๋ฌธ์— ํ•˜์ด๋ฒ„๋„ค์ดํŠธ ์˜ต์…˜์„ ์คŒ์œผ๋กœ์จ ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์—”ํ‹ฐํ‹ฐ ์ง์ ‘ ๋…ธ์ถœ

@GetMapping("/api/v1/orders")
public List<Order> ordersV1() {
List<Order> all = orderRepository.findAllByString(new OrderSearch());
for (Order order : all) {
order.getMember().getName(); //Lazy ๊ฐ•์ œ ์ดˆ๊ธฐํ™”
order.getDelivery().getAddress(); //Lazy ๊ฐ•์ œ ์ดˆ๊ธฐํ™˜
List<OrderItem> orderItems = order.getOrderItems();
orderItems.stream().forEach(o -> o.getItem().getName()); //Lazy ๊ฐ•์ œ
์ดˆ๊ธฐํ™”
}
return all;
}

LAZY๋กœ๋”ฉ์ด ๋˜์–ด์žˆ๋Š” ํ”„๋ก์‹œ๋ฅผ ๊ฐ•์ œ ์ดˆ๊ธฐํ™”์‹œ์ผœ์ฃผ์–ด์•ผํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•์€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ง์ ‘ ๋…ธ์ถœ์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์— ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋‹ค.

 

์—”ํ‹ฐํ‹ฐ๋ฅผ DTO๋กœ ๋ณ€ํ™˜

public List<OrderDto> ordersV2() {
List<Order> orders = orderRepository.findAll();
List<OrderDto> result = orders.stream()
.map(o -> new OrderDto(o))
.collect(toList());
return result;
}

Order ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์˜จ ๋’ค OrderDto ๋กœ ๋ณ€ํ™˜์‹œํ‚จ๋‹ค.์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•œ ์˜์กด์„ ์™„์ „ํžˆ ๋Š์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ์ˆœํžˆ Order์— ๋Œ€ํ•œ ์ •๋ณด๋งŒ์ด ์•„๋‹Œ, Item์— ๋Œ€ํ•œ ์ •๋ณด๋„ Dto๋กœ ๋ณ€ํ™˜์‹œํ‚จ๋‹ค.

static class OrderItemDto {
private String itemName;//์ƒํ’ˆ ๋ช…
private int orderPrice; //์ฃผ๋ฌธ ๊ฐ€๊ฒฉ
private int count;
//์ฃผ๋ฌธ ์ˆ˜๋Ÿ‰
public OrderItemDto(OrderItem orderItem) {
itemName = orderItem.getItem().getName();
orderPrice = orderItem.getOrderPrice();
count = orderItem.getCount();
}
}

ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ  ๋˜๋ฉด ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์—ฌ๋Ÿฌ ๋ฒˆ์˜ ์ง€์—ฐ๋กœ๋”ฉ์ด ๋ฐœ์ƒํ•  ๋•Œ๋งˆ๋‹ค ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— 1+N ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

EX) ์ฃผ๋ฌธ 1๊ฐœ ,  ์ฃผ๋ฌธ ์ •๋ณด N๊ฐœ , ์ฃผ๋ฌธ ์ƒํ’ˆ M๊ฐœ ->1 + N + M ๋ฒˆ์˜ ์ฟผ๋ฆฌ ๋ฐœ์ƒ

 

 

์—”ํ‹ฐํ‹ฐ๋ฅผ DTO๋กœ ๋ณ€ํ™˜- ํŒจ์น˜ ์กฐ์ธ ์ตœ์ ํ™”

public List<Order> findAllWithItem() {
return em.createQuery(
"select distinct o from Order o" +
" join fetch o.member m" +
" join fetch o.delivery d" +
" join fetch o.orderItems oi" +
" join fetch oi.item i", Order.class)
.getResultList();
}

์ด์ฒ˜๋Ÿผ ํŽ˜์น˜ ์กฐ์ธ์„ ํ†ตํ•ด ์ตœ์ ํ™”๋ฅผ ํ•ด์ฃผ๋ฉด , ์ฟผ๋ฆฌ๊ฐ€ ํ•œ๋ฒˆ๋งŒ ์‹คํ–‰๋จ์œผ๋กœ์จ ๊ธฐ์กด 1+N ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

JPA ์ฟผ๋ฆฌ๋ฌธ์˜ distinct ๋Š” ๋‘ ๊ฐ€์ง€ ๊ธฐ๋Šฅ์„ ํ•œ๋‹ค.

1. SQL ์— distinct  ์ถ”๊ฐ€

2. ๊ฐ™์€ ์—”ํ‹ฐํ‹ฐ ์ค‘๋ณต ์ œ๊ฑฐ

 

ํ•˜์ง€๋งŒ , ์ด ์ฝ”๋“œ์—์„œ ํŽ˜์ด์ง•์„ ํ•˜๊ฒŒ ๋˜๋ฉด DB๊ฐ€ ์•„๋‹Œ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํŽ˜์ด์ง•์„ ํ•ด๋ฒ„๋ฆฐ๋‹ค.

์ด๊ฒƒ์€ ๋ฉ”๋ชจ๋ฆฌ ์ดˆ๊ณผ(out of memory)๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๋งค์šฐ ์œ„ํ—˜ํ•œ ํ–‰์œ„์ž„์œผ๋กœ ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

* ์ปฌ๋ ‰์…˜ ํŽ˜์น˜ ์กฐ์ธ์€ 1๊ฐœ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‘˜ ์ด์ƒ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ ๋ถ€์ •ํ•ฉ ๋ฐœ์ƒ

 

 

์—”ํ‹ฐํ‹ฐ๋ฅผ DTO๋กœ ๋ณ€ํ™˜- ํŽ˜์ด์ง• ์ ์šฉ

์•ž์„  ์ฝ”๋“œ์—์„œ ํŽ˜์ด์ง•์ด ์•ˆ๋๋˜ ์ด์œ ๋Š” ์ผ๋Œ€๋‹ค ์กฐ์ธ์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†์ด ์ฆ๊ฐ€(N)ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ ํŽ˜์ด์ง•์„ ํ•˜๊ฒŒ๋˜๋ฉด ํŽ˜์ด์ง• ๊ธฐ์ค€์ด N ์— ๋งž์ถ”์–ด์ง„๋‹ค.

 

๋”ฐ๋ผ์„œ JPA๋Š” ์ด ๊ฒฝ์šฐ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š”๋ฐ ์ด๊ฒƒ์€ ๋งค์šฐ ์œ„ํ—˜ํ•˜๋‹ค !

 

์ผ๋Œ€๋‹ค ๊ด€๊ณ„์—์„œ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜๋ฉด ๋œ๋‹ค.

1. ToOne ๊ด€๊ณ„๋Š” ROW ์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค์ง€ ์•Š์œผ๋ฏ€๋กœ ํŽ˜์น˜ ์กฐ์ธ์„ ํ•œ๋‹ค.

2. ์ปฌ๋ ‰์…˜์€ ์ง€์—ฐ๋กœ๋”ฉ์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.

3. hibernate.default_batch_fetch_size , @BatchSize ๋ฅผ ์ ์šฉํ•œ๋‹ค. (DB์—์„œ ๋ฏธ๋ฆฌ ๋ถˆ๋Ÿฌ์˜ฌ ๋ฐ์ดํ„ฐ ์ˆ˜)

 

public List<Order> findAllWithMemberDelivery(int offset, int limit) {
return em.createQuery("select o from Order o" +
" join fetch o.member m" +
" join fetch o.delivery d", Order.class)
.setFirstResult(offset)
.setMaxResults(limit)
.getResultList();
}
spring:
jpa:
properties:
hibernate:
default_batch_fetch_size: 1000

ToOne ๊ด€๊ณ„๋ฅผ ํ•œ๋ฐฉ์ฟผ๋ฆฌ๋กœ ๊ฐ€์ ธ์˜ค๊ณ  ,  default_batch_fetch_size ๋ฅผ ์„ค์ •ํ•ด์ฃผ๋ฉด, ์„ค์ •ํ•œ ์‚ฌ์ด์ฆˆ๋งŒํผ ์ปฌ๋ ‰์…˜์€ in ์ฟผ๋ฆฌ์— ๋‹ด์•„์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

๋”ฐ๋ผ์„œ ๊ธฐ์กด 1+ N ์ด์—ˆ๋˜ ์ฟผ๋ฆฌ ์ˆ˜๊ฐ€ 1+1 ๋กœ ์ค„์–ด๋“ ๋‹ค. 

 

์‚ฌ์‹ค ToOne ๊ด€๊ณ„๋„ ๊ตณ์ด ํŽ˜์น˜ ์กฐ์ธ ์•ˆํ•ด๋„ ์ƒ๊ด€ ์—†๋Š”๋ฐ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฟผ๋ฆฌ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

 

๋งŒ์•ฝ ์กฐํšŒ ํ•  ๋ฐ์ดํ„ฐ ์ˆ˜๊ฐ€ 2๊ฐœ์ด๊ณ  ์‚ฌ์ด์ฆˆ๋ฅผ 1๋กœ ์„ค์ •ํ–ˆ์œผ๋ฉด , ์ฟผ๋ฆฌ๊ฐ€ ๋‘๋ฒˆ ์‹คํ–‰๋œ๋‹ค. (1 X 2)

๋งŒ์•ฝ ์กฐํšŒ ํ•  ๋ฐ์ดํ„ฐ ์ˆ˜๊ฐ€ 100๊ฐœ์ด๊ณ  ์‚ฌ์ด์ฆˆ๋ฅผ 10์œผ๋กœ ์„ค์ •ํ–ˆ์œผ๋ฉด , ์ฟผ๋ฆฌ๊ฐ€ ์—ด๋ฒˆ ์‹คํ–‰๋œ๋‹ค. (10 X 10)

 

์ด ๋ฐฉ๋ฒ•์€ ํŽ˜์น˜ ์กฐ์ธ์œผ๋กœ ํ–ˆ์„ ๋•Œ ๋ณด๋‹ค ์ฟผ๋ฆฌ๋Š” ์•ฝ๊ฐ„ ๋งŽ์ด ๋ฐœ์ƒํ–ˆ์„์ง€๋Š” ๋ชฐ๋ผ๋„ ๋ฐ์ดํ„ฐ ์ตœ์ ํ™”๊ฐ€ ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์€ ๋” ์ข‹๋‹ค.

ํ•˜์ง€๋งŒ ์†Œ๊ทœ๋ชจ ๋ฐ์ดํ„ฐ์ผ ๊ฒฝ์šฐ ํŽ˜์น˜ ์กฐ์ธ์œผ๋กœ ํ•˜๋Š” ๊ฒŒ ๋” ๋น ๋ฅผ ์ˆ˜ ์žˆ๋‹ค (์ƒํ™ฉ by ์ƒํ™ฉ)