개발 일기

[Spring Boot] 서비스 운영 관점에서 FK(외래키) 설정이 꼭 필요할까? 본문

Back-End/Spring

[Spring Boot] 서비스 운영 관점에서 FK(외래키) 설정이 꼭 필요할까?

개발 일기장 주인 2024. 8. 28. 16:30

평소에 데이터베이스를 설계할 때, 나는 외래 키를 무조건 설정하는 것이 당연하다고 생각했다. 실제 서비스에서든, 해커톤에서든, 외래 키를 통해 테이블 간의 참조 무결성을 유지하는 게 중요하다고 생각했다.

그런데 백엔드를 처음 해보는 친구와 함께 공부하다가, 그 친구가 나에게 "외래 키 설정 안해?"고 물었어다. 나는 당연히 키 설정을 한다고 했는데 친구는 블로그에서 보니까 외래 키를 설정하지 않는 곳도 있다고 답했다.

실제로 블로그를 좀 찾아보니 실제 운영 환경에서도 외래키를 설정안하는 개발자들도 꽤 보였다. 그래서 이 주제에 대해 조금 더 알아보기로 했고 몇몇 블로그를 참고하며 다른 사람들은 어떤 식으로 운영했는지 보게 됐다.


https://yeoon.tistory.com/165블로그 글에서 real mysql 8.0이라는 도서에

이렇게 실제로 서비스 DB에 FK 설정을 하지 않는다는 언급도 존재했다. 이 블로그 작성자 분께서 첫회사에서는 외래키가 DB의 성능 저하, 확장을 어렵게 만들고, 유연성을 잃게 만든다고 외래키를 사용하지 않았고 이직한 회사에서는 외래키가 제공하는 정합성, 무결성 유지 편익이 외래키가 없는 것 보다 크다고 하여 외래키 없이 1년, 외래키 사용하며 1년 서비스를 운영한 경험이 있다고 하셨다. 이 분의 생각을 종합해보면 

외래 키를 사용하지 않는 이유

  1. 관계가 단순할 때와 복잡할 때의 차이
    : FK는 두 테이블 간의 관계를 정의하는데, 테이블 간의 관계가 단순할 때는 큰 문제가 없지만, 관계가 복잡해질수록 FK가 성능 저하와 같은 문제를 야기할 수 있다.

  2. 성능 문제
    :
    FK는 기본적으로 인덱스로 설정하고 테이블에서 UPDATE 또는 DELETE 작업을 수행할 때 FK로 인해 추가적인 체크가 필요하고 이는 성능 저하로 연결된다. 또한 부모테이블, 자식테이블 모두 해당 컬럼 인덱스 생성이 필요하고, 변경 시 부모/자식 테이블 데이터 체크 과정이 필요하여 잠금이 발생한다. 이것이 데드락의 원인이 될 수 있다.
    ->  정리해보면 과도한 무결성 체크와 락 경합 감소로 성능 문제를 개선할 수 있다.

  3. 확장성 및 유연성 문제
    :
    FK가 존재하면 데이터베이스 스키마 변경이 어려워지고, 특히 데이터베이스 샤딩(sharding)이나 마이그레이션 시 FK가 장애물이 될 수 있다.
    복잡한 FK 관계가 있을 경우, 수동으로 데이터를 적재하거나 관리할 때 실수가 발생할 수 있다. 
    또한 FK가 있는 경우, 테이블 구조를 온라인 상태에서 변경하는 것이 어렵고, 이로 인해 운영 중인 시스템의 유연성이 떨어질 수 있다.

  4. 운영상의 제약
    FK에 CASCADE 옵션이 설정된 경우, 부모 테이블에서 데이터를 삭제할 때 자식 테이블의 데이터도 함께 삭제되는데, 이로 인해 원치 않는 데이터가 삭제될 위험이 있으며 테이블 간의 관계가 복잡한 경우, 긴급한 조치가 필요한 상황에서 FK 때문에 빠르게 대응하지 못할 수 있다.

 

외래키를 사용하지 않는다면?

개발 시 철저한 검증 강화
FK를 설정하지 않아서 발생할 수 있는 정합성 문제를 Validation을 Domain 및 Controller단에서 꼼꼼하게 실행하여 극복해준다.

Audit 데이터와 Soft Delete 사용을 통한 데이터 추적
FK 없이 데이터를 관리하려면 각 테이블에 감사(audit) 데이터를 남겨야 한다. 예를 들어, createdAt, lastModifiedAt, 작성자, 수정자 등의 정보를 저장하여 데이터의 변경 이력을 추적할 수 있어야 한다
또한 Soft Delete 처리로 항상 데이터를 추적할 수 있어야 한다.

 

 

 

여러 블로그를 조회해본 결과 

외래키는 애초에 데이터의 무결성(현재 데이터베이스에 존재하는 값이 틀리지 않았다는 것을 보장) 그리고 정합성(모든 데이터베이스 제약 조건을 만족)을 위해 사용하는 것인데 이로 인해 고려해야할 것이 많아지고 귀찮아지고 번거로워진다. 

무결성, 정합성을 포기하고 편의성 그리고 (피보팅을 대비한) 확장성을 챙기기 위해서 FK에 대한 설정을 하지 않는 것 같다고 느꼈다.

대신에 그만큼 Validation 등과 같은 로직에서 무결성과 정합성에 대한 신경은 어느정도 써줘야할 것 같다.