[생각정리] 외래 키(foreign key) 그만 알아보자!

선상원·2025년 2월 1일

생각정리

목록 보기
1/2

오늘의 주제는 "외래 키(foreign key)" 입니다.

외래키에 대해서 어떻게 생각하냐고 묻는 질문에 대부분의 엔지니어는
"설정하면 좋겠지만 불편한 점이 많은 것 같다" 라고 생각하는 분이 많은 것 같습니다.

어떤 점이 좋고 왜 불편한가? 라는 질문을 한다면 명쾌한 답변을 들을 수 없었는데요
저 역시 해당 게시글을 작성하며 생각을 정리하기 전까지는 명쾌한 답변을 할 수 없었을 것이라 생각이 듭니다.

최근 Foreign Key에 대해서 많은 기술 블로그를 읽어보았습니다.
블로그마다 각기 다른 생각을 이야기하며 Foreign Key에 대한 이슈를 설명했으며
주된 문제점은 "개발의 불편함""성능 저하" 문제였습니다.


🤔 Foreign Key의 주요 이슈

1️⃣ 개발의 불편함

Foreign Key를 설정할 경우,
참조 무결성 제약조건으로 인해 개발 시 많은 어려움이 있으며 그중에서도 가장 큰 불편함은 테스트 데이터를 만드는 것 일 텐데요.

Foreign Key를 설정하지 않는다면 필요한 테이블의 데이터만 생성해 테스트가 가능하지만, Foreign Key를 설정한다면 해당 테이블의 부모 테이블 여부 확인 + 부모 테이블 데이터 생성 등 추가 작업이 이루어지기 때문입니다.

그러나 저는 개발에 발생하는 불편함(테스트 데이터 생성)은
DISABLE NOVALIDATE 옵션 등을 통해서 제약조건을 OFF 시킬 수 있어 불편함을 해소할 수 있을 것이라고 생각합니다.

💡 DISABLE NOVALIDATE 옵션이란?

  • DISABLE: 제약조건을 비활성화하여 새로운 데이터 입력 시 검증하지 않음
  • NOVALIDATE: 기존 데이터에 대해서는 검증하지 않음
  • 즉, 제약조건은 존재하지만 실제로 작동하지 않는 상태

사용 예시 (Oracle):

ALTER TABLE 자식테이블 DISABLE NOVALIDATE CONSTRAINT FK_제약조건명;

⚠️ 주의사항:

  • 테스트 완료 후 다시 ENABLE VALIDATE로 전환 시, 기존 데이터의 정합성 문제가 있다면 에러 발생
  • 개발/테스트 환경에서만 사용하고, 운영 환경에서는 신중하게 판단 필요

2️⃣ 성능 저하

Foreign Key 설정으로 인한 성능 이슈는 두 가지 측면에서 발생합니다.

📊 Validation 검사 부하

DML 작업 시 FK 제약조건 검증을 위해 부모/자식 테이블 조회가 추가로 발생합니다.

  • 영향도: FK 컬럼에 인덱스가 적절히 설정되어 있다면 인덱스 스캔으로 처리되어 성능 영향은 미미
  • 주의점: 자식 테이블의 FK 컬럼에 인덱스가 없으면 부모 레코드 삭제 시 Full Table Scan 발생 가능

🔒 Lock 이슈 (주요 병목)

FK로 인한 실질적인 성능 저하는 Lock 전파에서 발생합니다.

발생 원리:

  • 자식 테이블 INSERT/UPDATE 시 부모 테이블의 참조 레코드에 공유 락(Shared Lock) 발생
  • 부모 레코드를 수정하려는 다른 트랜잭션이 대기 상태가 되어 동시성 저하
  • 복잡한 트랜잭션 구조에서 데드락(Deadlock) 발생 위험 증가

DBMS별 차이:

  • Oracle: MVCC 메커니즘으로 읽기 작업이 쓰기를 차단하지 않으며, Lock 경합 최소화
  • MySQL/InnoDB: Oracle과 유사하게 MVCC를 사용하지만, FK 제약 검증 시 부모 테이블에 shared record-level lock을 설정하여 동시성 환경에서 추가적인 Lock 경합 발생 가능

고트래픽 환경이나 실시간 처리가 중요한 금융권에서는 이러한 Lock 경합이 응답 시간 지연과 데드락 장애로 이어질 수 있어 FK 설정을 지양합니다.


🛠️ Foreign Key 설정 전략

그렇다면 Foreign Key 설정을 꼭 해야 하는 걸까요??
제가 생각하는 Foreign Key 설정 구성은 다음과 같은 방법이 있을 것 같습니다.

방안 1️⃣

운영DB 및 테스트DB 서버의 모든 테이블에 대해 Foreign Key 설정을 하되,
운영DB의 경우 성능 이슈가 존재하는 테이블에 대해서만 Validation 중지

구분Foreign Key 설정 여부Validation 설정 여부
테스트DBOO
운영DBOO (성능저하 테이블 제외)

방안 2️⃣

운영DB 및 테스트DB 서버의 모든 테이블에 대해 Foreign Key 설정을 하되,
운영DB의 경우 Validation 중지

구분Foreign Key 설정 여부Validation 설정 여부
테스트DBOO
운영DBOX

방안 3️⃣

운영DB 서버에는 Foreign Key 설정을 하지 않으며,
테스트DB 서버에서 Foreign Key 설정을 통해 데이터 검증

구분Foreign Key 설정 여부Validation 설정 여부
테스트DBOO
운영DBXX

📌 MySQL 사용 시 주의사항

다만, MySQL의 경우 Oracle처럼 테이블별로 Validation 설정을 할 수가 없어 FOREIGN_KEY_CHECKS 환경 변수 설정을 통해 전역으로 관리가 가능하다는 점을 참고해야겠습니다.


🎯 결론: 상황별 권장 전략

Foreign Key 설정에 대한 절대적인 정답은 없지만,
다음과 같은 기준으로 판단하는 것을 권장해볼 수 있을 것 같습니다.

📊 소규모 서비스 또는 트래픽이 낮은 경우

▶ 방안 1 추천: 운영/테스트 모두 FK 설정 + Validation 활성화

  • 데이터 무결성 보장의 이점이 성능 영향보다 큼

📈 중규모 서비스 (일부 테이블에서 성능 이슈 발생)

▶ 방안 1 추천: 문제되는 테이블만 선택적으로 Validation 중지

  • 무결성과 성능의 균형점 확보

🚀 대규모/실시간 서비스 (금융, 거래 시스템 등)

▶ 방안 2 또는 3 추천: 운영DB는 FK 미설정 또는 Validation 중지

  • 애플리케이션 레벨에서 데이터 정합성 관리 필수
  • 테스트DB에서 FK로 데이터 검증

💭 마무리

핵심은 "데이터 무결성"과 "성능" 사이의 트레이드오프를
서비스 특성에 맞게 조율하는 것입니다.

DBA는 서비스의 QPS, 데이터 중요도, 개발 편의성 등을
종합적으로 고려하여 최적의 전략을 수립해야 합니다.

기업의 서비스 규모, QPS 등 다양한 관리 포인트에 따라서 Foreign Key 설정 유무가 달라질 것으로 보이기 때문에 DBA는 이러한 요소를 고려하여 데이터베이스를 관리할 수 있어야 한다고 생각합니다.


💡 핵심 포인트

▶ Foreign Key 성능 이슈의 진짜 원인은 Validation 검사가 아닌 Lock 전파
▶ FK 컬럼에 인덱스 설정은 필수 (Full Table Scan 방지 + Lock 최소화)
▶ 고동시성 환경에서는 FK로 인한 데드락 리스크를 반드시 고려해야 함
▶ DBMS별 Lock 메커니즘 차이를 이해하고 서비스 특성에 맞는 전략 수립 필요

profile
쉼 없는 고민과 학습을 통해 가장 효율적인 데이터베이스 관리 방안을 찾고자 노력하는 DBA 입니다.

0개의 댓글