• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    해결됨

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

21.09.29 15:39 작성 조회수 1.47k

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는 이런 중복 체크가 필요없이 때문에 데이터를 추가할 때 초기화가 발생하지 않습니다.

감사합니다.

3

Herb님의 프로필

Herb

질문자

2021.09.30

 

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

결론적으로는 말씀해주신대로 (양방향 연관관계 + 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

Herb님의 프로필

Herb

질문자

2021.09.30

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

0

이국준님의 프로필

이국준

2022.12.17

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

 

좋은 질문 감사합니다!