simDev1234
심플하고 차분하게
simDev1234
전체 방문자
오늘
어제
  • 분류 전체보기
    • Computer Science
      • Basic Math
      • Data Structure
      • Algorithm
      • Database
      • OS
    • Language
      • Java
      • Kotlin
      • SQL
    • Framework
      • Spring
      • Orm&Mapper
      • 프로젝트로 스프링 이해하기
      • 스프링 라이브러리
    • Infra
      • Cloud
      • Docker
      • Redis
      • AWS, Azure
      • Device
    • Etc
      • CleanCoding
    • Git,Github

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • JVM메모리구조
  • 자바
  • 참조타입
  • 404
  • 참조변수
  • null
  • controllerTest
  • 자바프로그래밍
  • 스프링
  • 컨트롤러
  • 자바프로그램
  • scanner #next() #nextLine()
  • 자바메모리구조

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
simDev1234

심플하고 차분하게

Framework/Orm&Mapper

[Entity] 중복데이터 저장 방지 (Unique Key, Index)

2022. 11. 11. 12:14

|  관련 SQL 개념

(1) Unique Key : 중복 데이터 저장을 방지하기 위한 제약조건

- 단일 칼럼 뿐 아니라, 복합 칼럼을 지정할 수도 있다.

- 아래와 같이 복합 키를 생성할 경우, DB 조회 속도를 향상시킬 수 있다. 

-- MySQL 기준
create table member(
    email varchar(50),
    name  varchar(255),
    unique key member_uk_email (email, name)
)

- 중복 데이터 저장을 막기 위한 방법으로 아래 두가지를 사용할 수 있다.

  * 단순 insert into 문의 경우 에러를 발생하지만, 아래 두 가지는 에러를 발생시키지 않는다.

INSERT IGNORE unique key가 걸린 칼럼에 중복 데이터가 이미 있는 경우 삽입 X
INSERT ~~~ ON DUPLICATE KEY UPDATE unique key가 걸린 칼럼에 중복 데이터가 이미 있는 경우 업데이트
insert ignore into member values ('jamie@gmail.com','JAMIE');

-- 0 raw affected (error x)
insert ignore into member values ('jamie@gmail.com','JAMIE');
insert ignore into member values ('jamie@gmail.com','JAMIE');
insert ignore into member values 
   on duplicate key update ('jamie@gmail.com','JAMIE');

-- 2 raw affected (error x)
insert ignore into member values 
   on duplicate key update ('jamie@gmail.com','JAMIE');
   
insert ignore into member values 
   on duplicate key update ('jamie@gmail.com','JAMIE');

(2) Index : 추가적인 쓰기 작업과 저장공간을 활용해 DB table의 검색 속도를 향상시키기 위한 자료구조

- Index는 다양한 자료구조를 통해 만들 수 있다.(ex. Hashtable)

- 가장 많이 사용되는 자료구조는, B+Tree 구조이다.

  * B+Tree 구조란, DB인덱스를 위해 자식노드가 2개 이상인 B-Tree를 개선시킨 자료구조를 말한다.

  * 일반적으로 조회시 O(logN)의 시간을 가진다.

- Index는 아래처럼 두 가지로 종류를 나눌 수 있다.

cluster index primary key를 통해 인덱스를 설정 (ex. 처음부터 정렬된 영어사전)
보조 index unique key를 통해 인덱스를 설정 (ex. 책 뒤의 찾아보기)

  * 참고 ) 

   cluster와 보조index를 같이 쓸 경우 INDEX로 입력할 수 있지만, 보조 index만 쓸 경우 UNIQUE INDEX를 써야한다.

  * 자세한 내용 : https://enterkey.tistory.com/417

- Index는 아래와 같이 테이블을 생성할 때 만들 수도 있고, 별도로 alter문으로 제약조건을 붙일 수도 있다.

create table member(
    id    bigint  primary key,  -- cluster key 
    email varchar(50),
    name  varchar(255),
    
    unique key member_uk_email (email, name),
    INDEX  member_idx (id, email)
)

- Index의 장단점

장점 - Index를 사용하면 조회 속도를 향상시킬 수 있어, DB 서버의 부하를 줄일 수 있다.
단점 - 하지만 추가 저장공간을 사용해야하고,
- insert, update, delete 같은 데이터 변경 쿼리가 자주 사용되는 경우에 인덱스를 쓰면
   paging이 빈번해져 성능이 악화될 수 있다.(== 조회 보다 db 변동이 많은 경우 불리)
- 추가적으로 cardinality가 낮은 경우(= 중복 데이터가 많은 경우), 인덱스를 사용하는 것이 비효율적일 수 있다.

   * Selectivility : 데이터 집합에서 특정 값을 얼마나 잘 골라낼 수 있는지에 대한 지표

      >> Selectivility = Cardinality / Total number of Records

      >> Selectivility = 1 <-- 모든 레코드가 유니크하다.

   * cardinality : 특정 데이터 집합의 유니크(Unique)한 레코드의 개수 

- Index를 설계할 때 알아둘 점

[효율적인 인덱스 설계 ]
- Where절에 사용되는 열
- Select절에 자주 등장하는 칼럼을 잘 조합해 Index로 만들면 조회 시간을 줄일 수 있다.
- JOIN절에 자주 사용되는 열
- Order by 절에 사용되는 열은 클러스터 인덱스가 유리하다.

[금지해야할 인덱스 설계]
- 대용량 데이터가 자주 입력되는 경우 primary보다 unique를 설정한다.
- 데이터 중복도가 높은 열은 인덱스 효과가 없다. (ex. 성별)
- 자주 사용되지 않으면 성능 저하를 초래할 수 있다.

 

|  스프링에서 중복 데이터 저장을 방지하기

1. Primary key 설정하기

-  사용할 칼럼에 @Id 를 넣어준다.
- @GeneratedValue 를 통해 auto_increment가 가능하게 한다.

  * auto : 자동선택, identity : db identity 칼럼 사용, sequence : 시퀀스를 쓰는 db vendor에서 사용

2. Unique Key & Index 설정

- @Entity 클래스에서, @Table(uniqueConstraints = {}) 를 통해 unique 제약조건을 설정한다.

- Unique key를 아래와 같이 설정하게 되면 해당 키를 곧 인덱스로 인식한다.

@Entity(name = "DIVIDEND")
@NoArgsConstructor
@Getter
@ToString
@Table( // 복합 unique키 설정 (중복 저장 X)
        uniqueConstraints = {
                @UniqueConstraint(
                        columnNames = {"companyId", "date"}
                )
        }
)
public class DividendEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Long companyId;

    private LocalDateTime date;

    private String dividend;

    public DividendEntity(Long companyId, Dividend dividend) {
        this.companyId = companyId;
        this.date = dividend.getDate();
        this.dividend = dividend.getDividend();
    }
}

 

[ 참고 및 출처]

* 부트캠프 수업 내용 정리

* 인덱스 개념 참조 : https://mangkyu.tistory.com/96

* Cardinality와 Selectivility : https://soft.plusblog.co.kr/87

* 인덱스 핵심 설계 문법 : https://inpa.tistory.com/entry/MYSQL-%F0%9F%93%9A-%EC%9D%B8%EB%8D%B1%EC%8A%A4index-%ED%95%B5%EC%8B%AC-%EC%84%A4%EA%B3%84-%EC%82%AC%EC%9A%A9-%EB%AC%B8%EB%B2%95-%F0%9F%92%AF-%EC%B4%9D%EC%A0%95%EB%A6%AC

* 유니크 키를 통한 중복데이터 관리방법 https://umanking.github.io/2021/07/05/mysql-duplicate-record/

'Framework > Orm&Mapper' 카테고리의 다른 글

[JPA] CascadeType : 상위 -> 하위 엔터티 전파 타입  (0) 2022.11.28
[JPA] Lazy Loading 개념  (0) 2022.11.11
[Transaction] Transaction에 대한 이해 (& 스프링의 @Transactionl)  (1) 2022.10.25
[JPA] 인텔리J에서 JPA Entity 기반 ERD 그리기  (0) 2022.10.19
[JPA] repository.save()의 반환값이 안 들어올 때  (0) 2022.10.19
    'Framework/Orm&Mapper' 카테고리의 다른 글
    • [JPA] CascadeType : 상위 -> 하위 엔터티 전파 타입
    • [JPA] Lazy Loading 개념
    • [Transaction] Transaction에 대한 이해 (& 스프링의 @Transactionl)
    • [JPA] 인텔리J에서 JPA Entity 기반 ERD 그리기
    simDev1234
    simDev1234
    TIL용 블로그. * 저작권 이슈가 있는 부분이 있다면 댓글 부탁드립니다.

    티스토리툴바