RDBMS 모델링에서는 키 에 대한 정의가 세분화 되어 있다. 논리 모델링과 물리 모델링 에서 쓰여지는 키가 각각 다름에도 통용적으로 얘기가 되다 보니 헷갈려 하는 사람이 많다. 적어도 나는 공부할 때 많이 헤맸었다. 각각의 키에 대해서는 따로 정리 해둔 글이 있음으로, 해당 글의 설명으로 대체하겠다. https://glqdlt.tistory.com/528
개인적으로는 가상키를 PK로 많이 쓰는 편이다. 컬럼 이름은 id 이고 타입은 Integer 이며 auto increment 옵션을 둔다. 그냥 단순 증가 정수를 PK로 쓴다. 그런데 가끔은 클러스터링 군집화 때문에 복합PK를 정의해야할 때도 있다, 이럴 땐 단순 증가 정수 유니크컬럼을 추가로 만들고 JPA 엔티티 상에서는 ID 인 마냥 쓰기도 한다. 단지 레코드만 식별하기 위한 키를 가상키라 한다. 정확히는 도메인과 무관하게 레코드만 식별하는 키를 뜻한다. 이러는 이유는 JPA 의 엔티티 관계 설정이 단조로워지기 때문이다. 엔티티의 식별 ID 를 복합키로 쓰고 여러 엔티티에서 참조했을 때의 고통은 해본 사람만이 알 수 있다.
그러나 가상키가 마냥 좋은 것은 아니다. 명확한 단점이 있다. 클러스터링 군집화가 상황에 따라서 최악으로 발생한다는 것과 정규화 문제가 뒤따라온다는 점이다. 단점 까지는 아니지만 복합PK가 아닌 복합유니크 컬럼을 후보키로 하여 사용하면 생기는 문제도 있다. 복합유니크 컬럼은 null 을 허용할 수 있기 때문에 식별값을 정확히 유니크가 되지 않을 수 있다. null 로 도배된 동일한 식별값이 무수히 많아진다. 물론 null 허용을 금지하는 것으로 하면 쉽게 해결 할 수 있는 문제지만.
정규화 문제는 무슨 말일까? 가상키를 식별키로 쓰다보면 아노말리가 발생할수 있다. 가상키는 어떻게 보면 속성을 압축한 것과도 같다. 복합PK는 레코드의 속성이 포함 되어 있지만, 가상키에는 이러한 개념이 없다. 따라서 가상키는 속성이 포함되어 있지 않기 때문에 외부 릴레이션에서 아노말리가 생길 수 있다.
예를 들어보자.
테이블 4개가 있다고 하겠다.
| id | 과목 분류 |
|---|---|
| C | 컴퓨터 공학 |
| M | 수학 |
| id | 과목 이름 |
|---|---|
| C001 | 컴퓨터 공학 이론 |
| C002 | 이산수학 |
| M001 | 집합론 |
수강 과목 테이블
| 가상키 | 과목분류id | 과목id |
|---|---|---|
| 1 | C | C001 |
| 2 | C | C002 |
| 3 | M | M001 |
| seq | 수강과목_가상키 | 과목분류_id | 수강학생 | 날짜 |
|---|---|---|---|---|
| 99 | 1 | C | 김아무개 | 2025-01-01 |
| 98 | 1 | C | 박아무개 | 2025-01-01 |
| 97 | 2 | C | 김아무개 | 2025-01-01 |
이러한 테이블 설계는 실무에서 종종 나온다. 과목분류와 과목 이름의 관계를 의미하는 수강 과목 테이블이 있고, 수강 과목 테이블을 수료한 로그 테이블이 있다. 수료 테이블에서는 수강 로그를 과목 분류로 필터링 하기 위해서 과목분류_id 라는 컬럼을 만들어 이 컬럼을 통해 필터링을 빠르게 조회할수도 있다. 문제는 아래와 같다. 수강과목 2번 레코드 컴퓨터공학(C),이산수학(C002) 의 관계를 다룬 레코드인데, 어떠한 외부적 환경 요인으로 인해 이산수학이 M 수학에 분류가 되어야 한다고 결정되었다고 하자.
| id | 과목 분류 |
|---|---|
| C | 컴퓨터 공학 |
| M | 수학 |
| id | 과목 이름 |
|---|---|
| C001 | 컴퓨터 공학 이론 |
| C002 | 이산수학 |
| M001 | 집합론 |
수강 과목 테이블
| 가상키 | 과목분류id | 과목id |
|---|---|---|
| 1 | C | C001 |
| 2 | M | C002 |
| 3 | M | M001 |
| seq | 수강과목_가상키 | 과목분류_id | 수강학생 | 날짜 |
|---|---|---|---|---|
| 99 | 1 | C | 김아무개 | 2025-01-01 |
| 98 | 1 | C | 박아무개 | 2025-01-01 |
| 97 | 2 | C | 김아무개 | 2025-01-01 |
이렇게 바뀐다면 2번 수강과목은 수학(M), 이산수학(C002) 가 될것이다. 문제는 97번 로그를 보면 수강과목_가상키는 2번을 가르키고 있기 때문에 join 연산으로 찾아들어가면 이산수학이 수학분류에 들어간것을 알수있지만, 로그에 빠른 필터링을 위해 만들어두었던 과목분류_id 컬럼은 여전히 컴퓨터공학(C)로 되어있어 문제가 발생한다. 수강로그 테이블의 과목분류_id 는 과목분류 테이블과 fk 관계에 있는 것도 유지가 되기에 도메인 무결성 에러도 발생하지 않아 정상인 것처럼 보이게 된다. 이것이 앞서 내가 말한 이상현상이 발생할 수 있다는 경우이다. 만약 가상키가 아닌 복합 식별 PK 를 사용했더라면 이러한 문제는 덜해진다. 복합PK 를 했다면 로그 테이블은 자연스레 수강과목 테이블의 복합PK(과목분류id, 과목id)를 맺었을테고, 로그 테이블에서 fk 로 의존하는 과목분류id 를 필터링 조건으로 조회하면 될 것이기 때문이다.
가상키는 일종의 기존 복합PK를 압축한 형태라고도 볼수 있는데, 복합키의 속성이 PK에 나타나지 않기 때문에 이러한 문제가 발생한다. 사실 이런 문제는 데이터 정합성(consistency) 문제에 가깝다. 본래라면 수강과목_가상키를 통해서(join 해서) 과목분류를 알아내는 것이 보편적이겠지만 join 을 피하기 위해서 이렇게 추가 컬럼을 정의하기도 한다. nosql 세상에서는 이런일이 빈번한데, 이를 Stale data 라 부른다. rdbms 에서는 stale column 이라 할수도 있겠으나, 이 보다는 derived column(유도된 컬럼), denormalized attribute (반정규화 속성)이라고 부른다.
다만 이것은 특정한 상황에서 발생할수있는 특수한 상황이고, 개인적으로는 가상키를 PK 사양으로 대부분 사용한고 있다. 여지껏 이러한 특수한 경우를 제외하고는 문제될 만한 것을 경험한 것이 없다.
복합pk와 가상키가 아닌 다른 주제에서도 데이터 정합성 문제는 발생할 수 있다. RDBMS 의 구조적 한계 때문에 가끔은 일부러 derived column 을 많이 만들어야 하는 경우도 있다. 기회가 된다면 다루겟지만 RDBMS 의 모델링은 그래프 자료구조 라던지 트리 계층 자료구조를 표현할수 없는 문제가 있어서 서비스가 커지거나 도메인이 풍부해지면 모델링 과정에서 문제에 빠지는 경우가 있다.
맛보기로 말하면 게시판과 댓글 관계는 단순하게 1:N 으로 표현할수 있지만, 댓글의 댓글, 대댓글과 같은 중첩 계층으로 표현이 되어야 하는 트리 자료구조 처럼 모델링해야할 때에는 많은 고민이 들것이다. 이를 해결하려면 모델링 디자인 패턴 (예: nested set, adjacency list, materialized path, closure table 등) 을 사용해야 하는데, 트리 자료구조를 표현 하기 위한 테이블을 만들고 또 만들고 하는 식으로 하게 되면서 지금과 유사한 아노말리 문제가 무조건 발생할 수 밖에 없다.
물론 이런 RDBMS 의 한계에 봉착했을 때에는 프로그래밍 패러다임(개발 방법론, 예를 들면 에릭에반스의 DDD 같은 것들)을 바꾼다던지, 아니면 전혀 다른 NOSQL 시스템을 도입한다던지 다른 방법론으로 접근을 해 해결할 문제이긴 하다. 이야기가 옆으로 셋지만 가상키를 PK로 쓰는 것이 무조건 옳다는 것은 아니고 편의상 쓴다는 점을 이해하고 아노말리 문제가 발생할 수 있다는 점을 인지해야 한다는 말로 맺겠다.
'Tech > mysql | DB모델링 | JPA' 카테고리의 다른 글
| JPA 에서는 int 를 써야하나요? integer 를 써야하나요? (1) | 2025.07.09 |
|---|---|
| 테이블 풀스캔이 인덱스 보다 성능이 더 좋다. (5) | 2025.07.04 |
| [250620] mysql 파티션은 만병통치약일까? (0) | 2025.06.20 |
| [240513] mysql varchar(65535) 는 정말 65535 개의 한글을 입력할수있는걸까? (4) | 2025.06.10 |
| [240513] MYSQL 모델링에서 TEXT 와 LONGTEXT 의 차이 (6) | 2025.06.04 |