인프런 커뮤니티 질문&답변

scorbiclife님의 프로필 이미지
scorbiclife

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

값 타입 컬렉션

Collection type으로 Set 대신 List를 사용하는 이유가 있는지요?

해결된 질문

작성

·

2.1K

11

[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예)
 
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요?
관련 질문: https://www.inflearn.com/questions/216545
추가 내용이 있습니다.

3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)

[질문 내용]
 
Collection type으로 Set 대신 List를 사용하시는 이유가 궁금합니다.
 
지금까지 나온 Collection들이 모두 unique한 Entity(또는 값 타입)들의 collection이기 때문에, Set을 활용할 경우 중복 확인 관련 부분이 깔끔해지고, 다른 질문의 답변에서 답해주신대로 값 타입 컬렉션에도 row를 모두 날리고 다시 넣는 문제를 막을 수 있어 Set에 대해 좋은 인상을 가지게 되었습니다.
 
그런데 기본적으로 예제가 List를 사용하여, Set을 사용하였을 때 제가 놓친 문제가 있는지 의문이 들었습니다.
 

답변 4

11

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. Catnip님

좋은 질문입니다. Set이 개념적으로 좋지만 실무에서는 성능 이슈가 있습니다.

Set은 중복을 제거해야 하는데, 그렇다는 것은 기존 데이터 중에 중복이 있는지 비교를 해야 합니다. 이게 일반적으로는 크게 문제가 없는데, 지연 로딩으로 컬렉션을 조회했을 때 문제가 됩니다.

컬력션이 아직 초기화 되지 않은 상태에서 컬렉션에 값을 넣게 되면 프록시가 강제로 초기화 되는 문제가 발생합니다. 왜냐하면 중복 데이터가 있는지 비교해야 하는데, 그럴러면 컬렉션에 모든 데이터를 로딩해야 하기 때문입니다.

반면에 List는 이런 중복 체크가 필요없이 때문에 데이터를 추가할 때 초기화가 발생하지 않습니다.

감사합니다.

안녕하세요!
그러면 List를 쓰는 것이 성능이 좋다는 말씀이신데,
데이터 중복 방지를 위해 또 다른 로직을 서비스단에 추가를 해야할까요?

아니면 사실상 데이터가 중복돼서 들어올 일이 없기 때문에 성능 이슈가 없는 리스트를 사용하는 것일까요?
예를 들어 좋아요 한 글들을 가져올 때 중복이 없이 가져오는 것이 중요할 것 같은데
리스트는 혹시라도 중복이 있을 수도 있지않을까 해서 여쭤봅니다!

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. jayjoy05님

일반적으로 데이터베이스에서 데이터를 조회하는 시점부터 데이터를 중복되지 않는 방식으로 조회합니다 🙂

DB에서 이미 중복을 다 제거하고 가져오기 때문에 List를 사용해도 대부분 이슈가 없습니다.

감사합니다.

db에서 중복을 제거하고 가져온다는 말씀이 잘 이해가 가질않는데,

보통 회원의 게시글을 가져올 경우

다대일 양방향매핑관계에서

user.getPostList()이렇게 가져오는거면 단순히 조인해서 가져오는건데 어느 부분에서 중복이 제거된다는 말씀이신지 궁금합니다

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. jayjoy05님

user.getPostList()를 호출하는 경우 해당 유저가 작성한 Post들이 조회되는데요.

이 경우에는 특정 사용자가 작성한 Post들만 조회되기 때문에 중복이 발생하지 않습니다.

감사합니다.

3

scorbiclife님의 프로필 이미지
scorbiclife
질문자

 

말씀해주신 내용을 확인해본 결과로, 혹시 찾아오신 분들께 도움이 될까 싶어 공유합니다.

결론적으로는 말씀해주신대로 (양방향 연관관계 + List)를 취하면 불필요한 fetch가 없을 것 같습니다.

1. 값 타입의 Collection을 변경시킬 경우 말씀대로 Set에서는 데이터가 로딩되고 List에서는 데이터가 로딩되지 않음을 확인하였습니다.

2. 반면 1:N 단방향 연관관계에서는 Collection을 변경시킬 경우 Set, List 모두 데이터가 로딩됨을 확인하였습니다.

(추가)

3. 우리가 N:1 양방향 연관관계의 mappedBy에서도 Set에서만 데이터가 로딩된다는 내용의 Documentation을 찾고 확인하였습니다.

다만 해당 자료는 최근 버전에서 없어지거나 이동한 것으로 보입니다.

옛날 버전(Hibernate 4.3): https://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html/ch20.html#performance-collections-mostefficientupdate

최근 버전(Hibernate 5.4): https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#best-practices-mapping-associations

=====

2022/05/29 수정 - Github Gist로 관련 파일만 옮겼습니다.

제가 사용한 코드입니다 (https://gist.github.com/nightlyherb/00447a2ab196dcc3d5cd9e9b01f313ef)

관련 부분

DemoRunner.java

결과

===== Init Lazy Parent =====
Hibernate:
    select
        parent0_.id as id1_1_0_
    from
        parent parent0_
    where
        parent0_.id=?
===== Embeddable Child Set =====
Hibernate:
    select
        embeddable0_.parent_id as parent_i1_2_0_,
        embeddable0_.value as value2_2_0_
    from
        parent_embeddable_child_list embeddable0_
    where
        embeddable0_.parent_id=?
===== Embeddable Child List =====
===== Entity Child Set =====
Hibernate:
    select
        entitychil0_.set_parent_id as set_pare2_0_0_,
        entitychil0_.id as id1_0_0_,
        entitychil0_.id as id1_0_1_
    from
        entity_child entitychil0_
    where
        entitychil0_.set_parent_id=?
===== Entity Child List =====
Hibernate:
    select
        entitychil0_.list_parent_id as list_par3_0_0_,
        entitychil0_.id as id1_0_0_,
        entitychil0_.id as id1_0_1_
    from
        entity_child entitychil0_
    where
        entitychil0_.list_parent_id=?
===== Bidirectional Mapping Child Set =====
Hibernate: 
    select
        bidirectio0_.set_parent_id as set_pare3_0_0_,
        bidirectio0_.id as id1_0_0_,
        bidirectio0_.id as id1_0_1_,
        bidirectio0_.list_parent_id as list_par2_0_1_,
        bidirectio0_.set_parent_id as set_pare3_0_1_ 
    from
        bidirectional_mapping_child bidirectio0_ 
    where
        bidirectio0_.set_parent_id=?
===== Bidirectional Mapping Child List =====
===== End =====

(그 후 Embeddable Child List의 테이블 전부 날리고 다시 insert하는 쿼리 수행)

 

 

 

 

김영한님의 프로필 이미지
김영한
지식공유자

Catnip님 감사합니다^^

1

scorbiclife님의 프로필 이미지
scorbiclife
질문자

정말 생각지도 못한 문제가 있었네요! 답변 감사드립니다!

0

저도 이 부분이 궁금했었는데, 이런 성능 이슈가 있었군요 🤔

 

좋은 질문 감사합니다!

scorbiclife님의 프로필 이미지
scorbiclife

작성한 질문수

질문하기