Relational Model Table Key Constraint
3줄 요약
- 관계형 모델은 데이터를 테이블에 넣는 문법이 아니라 중복, 무결성, 관계를 명시적으로 관리하는 사고방식이다.
- Primary Key, Foreign Key, Unique, Check, Not Null 같은 제약은 애플리케이션 검증의 보조가 아니라 DB가 마지막으로 지켜야 하는 데이터 계약이다.
- 백엔드 개발자는 “코드에서 막는다”와 “DB에서 보장한다”를 구분하고, 장애나 동시성 상황에서도 깨지면 안 되는 규칙은 제약으로 내려야 한다.
핵심 정리
- Table은 같은 성격의 사실을 행으로 모은 구조다. 한 행은 식별 가능해야 하고, 한 컬럼은 가능한 한 하나의 의미를 가져야 한다.
- Primary Key는 행의 정체성이다. 화면에 보이는 값이나 변경 가능한 비즈니스 값보다 안정적인 식별자를 선택해야 한다.
- Foreign Key는 테이블 간 참조 무결성을 DB가 보장하게 만든다. 애플리케이션 코드에서만 삭제 순서를 관리하면 배치, 운영 쿼리, 장애 복구 때 깨질 수 있다.
- Unique 제약은 중복 가입, 중복 주문 번호, 중복 좋아요 같은 비즈니스 불변식을 동시성 상황에서도 막는다.
exists로 먼저 검사하는 코드는 레이스 컨디션에 약하다.
- Check와 Not Null은 잘못된 상태가 저장되는 것을 줄인다. 모든 검증을 서비스 코드에만 두면 다른 코드 경로에서 데이터가 오염될 수 있다.
- 제약은 비용도 있다. FK는 삭제와 변경 순서를 엄격하게 만들고, Unique는 인덱스 비용을 만든다. 그래도 정합성이 중요한 규칙은 코드보다 DB 제약이 마지막 방어선이다.
- 운영 중인 큰 테이블에 제약을 추가할 때는 기존 데이터 검증, lock 범위, index 생성 방식, 배포 순서를 함께 봐야 한다. 좋은 제약도 추가 과정이 거칠면 장애가 될 수 있다.
헷갈리는 지점
- 제약 조건은 개발 속도를 늦추는 귀찮은 장치라고 생각하기 쉽다. 테스트 데이터 넣을 때 불편함이 먼저 느껴지기 때문이다.
- 핵심은 제약이 운영 데이터의 마지막 안전장치라는 점이다.
- 불편한 제약이 아니라 비즈니스 계약을 잘못 모델링한 제약인지 먼저 봐야 한다.
- FK를 쓰면 무조건 성능이 나쁘다고 오해하기 쉽다. FK가 쓰기 경로에서 참조 검사를 하기 때문이다.
- 핵심은 성능 비용과 정합성 보장의 교환이다.
- 트래픽, 삭제 패턴, 운영 편의성, 데이터 중요도를 보고 판단해야 한다.
- PK는 그냥 자동 증가 숫자면 된다고 생각하기 쉽다. 대부분 예제가
id를 쓰기 때문이다.
- 핵심은 PK가 내부 식별자인지, 외부에 노출되는 식별자인지 구분하는 것이다.
- 외부 노출 ID, 샤딩 가능성, 추측 가능성, 정렬 의미를 함께 고려해야 한다.
- 제약은 새 테이블을 만들 때만 고민하면 된다고 생각하기 쉽다. 실제 운영에서는 이미 쌓인 데이터 위에 제약을 추가해야 하는 일이 많기 때문이다.
- 핵심은 제약 추가 전 기존 데이터가 조건을 만족하는지 먼저 검증하는 것이다.
- 큰 테이블에서는 검증 쿼리, lock, index 생성, rollback 계획을 배포 계획에 포함해야 한다.
확인 질문
- Unique 제약이 애플리케이션의 중복 검사보다 강한 이유는 무엇인가?
- 동시 요청이 동시에
exists 검사를 통과해도 DB의 Unique 제약은 최종 쓰기 시점에서 중복 저장을 막을 수 있기 때문이다.
- Foreign Key를 쓰지 않을 때 백엔드 개발자가 추가로 감당해야 하는 책임은 무엇인가?
- 참조 무결성 검증, 삭제 순서, 고아 데이터 탐지, 운영 쿼리 안전성, 장애 복구 시 데이터 정합성을 애플리케이션과 운영 절차에서 직접 관리해야 한다.
- Not Null과 Check 제약은 왜 필요한가?
- 코드 경로가 늘어나도 DB에 저장되면 안 되는 상태를 마지막 단계에서 차단하기 위해서다.
- 운영 중인 테이블에 Unique나 FK를 추가하기 전에 확인해야 할 것은 무엇인가?
- 기존 중복/고아 데이터 여부, 제약 검증 비용, 필요한 인덱스, lock 영향, 배포 순서, 실패 시 rollback 또는 정정 계획이다.