Java/JPA 관련

[JPA] JPA Entity 왜 단일키가 좋은가?

jwKim96 2021. 10. 6. 13:00

대부분 Entity의 키는 단일키로 하는것이 좋다고 설명합니다.

왜 그럴까요?

제가 봤던 책에서는 Entity의 키에 대해서 다음과 같이 이야기 합니다.
(스프링 부트와 AWS로 혼자 구현하는 웹 서비스, 저자 : 이동욱)

왠만하면 Entity의 PK는 Long 타입의 Auto_increment를 추천합니다.(MySQL기준으로는 bigint타입)
주민등록번호와 같이 비즈니스상 유니크키 혹은 복합키로 PK를 잡을 경우 난감한 상황이 종종 발생함

1. FK를 맺을 때 다른 테이블에서 복합키를 모두 갖고있거나, 중간 테이블을 둬야하는 상황이 발생
2. 인덱스에 좋은 영향을 끼치지 못함
3. 유니크한 조건이 변경될 경우, PK전체를 수정해야 하는 일이 발생

하나씩 살펴봅시다.


1. FK를 맺을 때 다른 테이블에서 복합키를 모두 갖고있거나, 중간 테이블을 하나 더 둬야하는 상황이 발생

CREATE TABLE department (
    dept_no varchar(12),
    dept_name varchar(50)    
    CONSTRAINT PK_department PRIMARY KEY (dept_no, dept_name)
);

CREATE TABLE employee (
    emp_no varchar(12),
    emp_name varchar(50),
    emp_age int
    CONSTRAINT PK_employee PRIMARY KEY (emp_no)
);

위와 같은 테이블이 있다고 가정해 봅시다.

department 테이블은 dept_no, dept_name 이 두 컬럼을 복합키로 사용하도록 설계되어있습니다.

employee 가 어떤 department에 속해있는지 알아야 한다는 요건에 따라 다음과 같이 변경되었습니다.

CREATE TABLE department (
    dept_no varchar(12),
    dept_name varchar(50),
    CONSTRAINT PK_department PRIMARY KEY (dept_no, dept_name)
);

CREATE TABLE employee (
    emp_no varchar(12),
    emp_name varchar(50),
    emp_age int,
    dept_no bigint,        /* department 테이블 FK를 위해 추가 */
    dept_name varchar(50), /* department 테이블 FK를 위해 추가 */
    CONSTRAINT PK_employee PRIMARY KEY (emp_no)
);

그저 employee가 어떤 department에 속하는지만 알면 되는데, 모든 employeedept_no, dept_name

두 데이터를 항상 갖고있죠. 이렇게 복합키로 주게 되면, 필요 이상의 데이터를 갖게 될 수도 있기 때문에 불필요한

공간 낭비를 줄이기 위해서는 되도록이면 복합키 사용을 자제하는것이 좋습니다.

그리고 복합키로 된 테이블은 쿼리 조건문에 따라 Index가 제대로 사용되지 않을수도 있습니다.


2. 인덱스에 좋은 영향을 끼치지 못함

우리가 만약 department에서 dept_name이 'dev_team'인 row를 찾고싶다면,

SELECT * FROM department WHERE dept_name = 'dev_team'

이렇게 쿼리를 작성하고 실행할텐데, 이 쿼리는 인덱스가 사용되지 않습니다.

왜냐하면, PK_departmentdept_no, dept_name 두개의 컬럼을 함께 PK로 설정하였는데,

한개의 컬럼만 WHERE 조건문에서는 dept_name 한개의 컬럼만 사용되었기 때문입니다.

만약 이 테이블에 데이터가 많아, 어쩔수 없이 인덱스가 사용되도록 해야한다면?

SELECT * FROM department WHERE dept_no > 0 AND dept_name = 'dev_team'

아주 안좋은 예시지만, 위와 같이 쿼리를 수정하면 인덱스가 사용됩니다.

그런데 갑자기, 요건이 변경되어 dept_name 중복값이 들어가야 한다고 합니다.

그러면 어떻게 될까요?


3. 유니크한 조건이 변경될 경우, PK전체를 수정해야 하는 일이 발생

department의 PK는 dept_no, dept_name 두 컬럼으로 이루어져 있는데 앞서 변경된 요건을 위해서

PK_department 전체를 수정해야 합니다.


그러면 어떻게 하는게 최선일까?

글의 제일 처음에서 나왔던 대로, bigint 타입 auto_increment로 설정된 id 컬럼을 단일 PK로 설정하고,

비즈니스로직상 제약조건들이나 쿼리 성능개선을 위한 인덱스 등은 PK와 따로 설정하는것이 최선입니다.

REATE TABLE department (
    id bigint auto_increment,
    dept_no varchar(12),
    dept_name varchar(50),
    PRIMARY KEY (id)
);

ALTER TABLE department ADD UNIQUE UNIQUE_department (dept_no, dept_name);

이렇게 변경하면 위 3번과 같이 요건이 변경되었을 경우 PK에는 영향을 주지 않고,

UNIQUE_department 제약조건만 수정할 수 있습니다.