[JPA] JPA Entity 왜 단일키가 좋은가?
대부분 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
에 속하는지만 알면 되는데, 모든 employee
는 dept_no
, dept_name
두 데이터를 항상 갖고있죠. 이렇게 복합키로 주게 되면, 필요 이상의 데이터를 갖게 될 수도 있기 때문에 불필요한
공간 낭비를 줄이기 위해서는 되도록이면 복합키 사용을 자제하는것이 좋습니다.
그리고 복합키로 된 테이블은 쿼리 조건문에 따라 Index가 제대로 사용되지 않을수도 있습니다.
2. 인덱스에 좋은 영향을 끼치지 못함
우리가 만약 department
에서 dept_name
이 'dev_team'인 row를 찾고싶다면,
SELECT * FROM department WHERE dept_name = 'dev_team'
이렇게 쿼리를 작성하고 실행할텐데, 이 쿼리는 인덱스가 사용되지 않습니다.
왜냐하면, PK_department
는 dept_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
제약조건만 수정할 수 있습니다.