데이터베이스, ORM

RDB에서 외래키 사용하지 않는 이유?

SparkIT 2025. 3. 17. 10:19

저는 개발을 하면서 레거시 코드를 만져야 하는 경우가 몇 번 있었는데요. 이때마다 데이터베이스(RDB)에 외래키가 설정되지 않은 경우가 굉장히 많았습니다. 이로 인해 데이터베이스 관리 도구를 통해 전체 다이어그램을 보아도 스키마를 이해하기 어렵다는 문제가 발생했습니다. 기존에 저는 개발 공부를 하면서 데이터 무결성을 위해서는 외래키를 설정해야 한다고 알고 있었습니다. 하지만 실무에서 외래키가 적용되어있지 않는 사례가 너무 많다 보니 이에 대한 궁금증이 생겼습니다. 대체 외래키 없는 관계형 데이터베이스는 왜 존재하는 것일까요?

 

주장 1. 외래키로 인한 성능 저하

구글 검색창에 외래키만 검색해도 '외래키 안쓰는 이유', '외래 키 없이 개발' 등의 키워드가 뜨는 모습을 확인할 수 있습니다. 이는 꽤 많은 관계형 데이터베이스에 외래키가 설정되지 않고 사용되고 있음을 방증합니다. 조사 결과 외래키를 사용하지 않는 대표적인 이유는 성능 저하였습니다.

기본적으로 외래키를 사용하게 되면 CRUD 작업에 데이터 무결성을 위한 검증 과정이 추가로 필요합니다. 예를 들어 유저 테이블과 게시물 테이블이 있을 경우 게시물 테이블에 데이터를 추가하려할 때 게시물을 작성한 유저 정보가 게시물 데이터에 존재할 것이고, 해당 유저가 실제 유저 테이블에 존재하는지 검증이 필요합니다. 이런 검증이 성능에 문제를 일으킨다는 주장입니다.

하지만 저는 이런 주장에 동의할 수 없었습니다. 단순히 데이터베이스에서 연관관계 설정된 데이터가 존재하는지 검증하는 작업은 PK로 조회할 것이고 이는 성능에 굉장히 미비할 것이라고 생각했기 때문입니다. 저는 이를 직접 확인해보기 위해 아래와 같은 테스트를 진행했습니다. 먼저 A 데이터베이스와 B 데이터베이스를 생성한 뒤 동일한 구조의 user 테이블과 post 테이블을 생성했습니다. post 테이블에서는 어떤 user가 해당 post를 작성했는지 알 수 있게 하기 위해 user_id 컬럼을 생성했습니다. 이때 A 데이터베이스에서는 두 테이블에 외래키를 설정했고 B 데이터베이스에서는 외래키 설정을 하지 않았습니다.

 

- 삽입 INSERT

100만개의 post 데이터를 삽입해보았습니다. 이때 외래키가 설정된 A 데이터베이스에서는 6초, 외래키가 설정되지 않은 B 데이터베이스에서는 3초 정도 시간이 소요되었습니다. 확실히 외래키가 없는 경우가 데이터를 삽입하는 과정이 빨랐습니다. A 데이터베이스에서 3초가 더 걸린 이유는 데이터를 삽입할때마다 참조 무결성 검사가 일어나기 때문일 것입니다.

 

- 조회 SELECT

JOIN을 활용한 post 데이터와 user 데이터를 동시에 조회해보았습니다. 이때 A 데이터베이스와 B 데이터베이스는 둘 다 1초도 안 걸렸습니다. 이때 B 데이터베이스에서도 A 데이터베이스와 동일하게 PK 설정으로 인한 인덱스 설정이 되어있기 때문에 성능에 차이가 없는 것으로 판단되었습니다.

 

- 수정 UPDATE

수정 테스트를 위해 post 테이블에 한 명의 user id로 100만개 데이터를 추가했습니다. 또한 A 데이터베이스에서 user 테이블에 On Update Cascade 설정을 적용했습니다.

외래키를 설정하지 않은 B 데이터베이스에서는 user 데이터 하나를 수정해도 정말 user 테이블에서 데이터 하나만 수정하는 것일뿐이므로 1초도 안 걸리게 빠르게 처리되었습니다. 하지만 외래키가 설정된 A 데이터베이스에서는 user 데이터를 수정(이때 수정은 user 데이터의 pk값 수정을 의미)할 경우 해당 user 데이터와 연결된 post 데이터가 모두 같이 수정되어야했으므로 6 정도 처리 시간이 걸렸습니다.

 

- 삭제 DELETE

삭제 테스트를 위해 post 테이블에 한 명의 user id로 100만개 데이터를 추가했습니다. 또한 A 데이터베이스에서 user 테이블에 On Delete Cascade 설정을 적용했습니다.

외래키를 설정하지 않은 B 데이터베이스에서는 user 데이터 하나를 삭제해도 정말 user 테이블에서 데이터 하나만 삭제하는 것일뿐이므로 1초도 안 걸리게 빠르게 처리되었습니다. 하지만 외래키가 설정된 A 데이터베이스에서는 user 데이터를 삭제할 경우 해당 user 데이터와 연결된 post 데이터가 모두 같이 삭제되어야했으므로 대략 7초 정도 처리 시간이 걸렸습니다.

 

✅ 정리

즉, 100만개의 데이터를 이용한 CRUD 테스트 결과는 다음과 같습니다.

  외래키 O 외래키 X
삽입 6초 3초
조회 1초 1초
수정 6초 1초
삭제 7초 1초

전체적으로 외래키를 사용하지 않았을 때 CRUD 속도가 더 빠르다는 것을 알 수 있습니다.

하지만 저는 여기서 외래키를 사용하지 않고 성능을 올리는 부분에 대해 재고할 필요성이 있다고 생각합니다. 위 테스트는 한 번에 100만개의 데이터를 CRUD 하는 테스트였습니다. 여기서 생기는 속도 차이는 평균적으로 4~5초 차이였는데요. 데이터베이스 레벨에서 보장되는 무결성을 포기하고 이 정도의 속도 향상을 얻어내는 것이죠. 이때 고려할 부분은 과연 이렇게 많은 데이터를 한 번에 CRUD하는 경우가 필요한가입니다. 만약 내가 개발하고 있는 시스템이 대용량 데이터를 다룬다면 데이터베이스 레벨에서의 데이터 무결성 검사를 포기하고 성능을 위해 외래키를 제거하는 것이 좋을 수도 있다고 생각합니다. 하지만 그렇지 않은 경우는 데이터베이스 레벨에서의 무결성 검사라는 이점을 가져가는 것이 더 좋다고 생각합니다.

 

 


주장2. 유연한 수정 불가

위에서 진행했던 UPDATE, DELETE 테스트와 비슷한 내용입니다. 아무래도 외래키를 설정하게 되면 부모 테이블의 PK값을 수정하거나 삭제할 때 자식 테이블에도 영향이 가기 때문에 쉽게 수정이나 삭제가 불가합니다. 예를 들어 부모 테이블에서 PK값으로 INT를 사용하고 있었고 자식 테이블에서는 이를 FK로 사용하고 있다고 가정합니다. 이후 개발 과정에서 부모 테이블의 PK를 INT 대신 VARCHAR 타입으로 수정해야할 필요가 제기되어 이를 수정한다면 어떻게 될까요? 자식 테이블에서 부모 테이블의 PK를 FK로 참조하고 있기 때문에 해당 작업은 데이터베이스단에서 막힙니다.

물론 방법이 없는 것은 아닙니다. 먼저 자식 테이블에서 FK 설정을 삭제합니다. 그리고 부모 테이블 PK 타입을 수정하고, 자식 테이블 FK 타입도 똑같이 수정해줍니다. 그리고 다시 자식 테이블에서 FK 설정을 추가하면 성공적으로 위 작업을 마칠 수 있습니다. 하지만 여기서 문제가 되는 것은 실제 서비스중인 데이터베이스에 위와 같은 작업을 진행할 수 있느냐입니다. 아직 배포가 되지 않은 상태에서는 위와 같은 작업을 편하게 진행할 수 있겠지만 만약 이미 배포되어 실제 사용자들이 사용중인 서비스의 데이터베이스에 위와 같은 작업을 진행할 수 있을까요? 위 작업으로 인해 해당 테이블을 사용하는 모든 트랜잭션이 중지될 위험도 있고, 해당 테이블에 데이터가 너무 많다면 작업이 너무 오래 걸려 문제가 될 수도 있겠죠.

 

 


주장3. MSA 에서 사용 불가

MSA를 사용하게 되면 여러 서비스가 각자의 DB를 가지게 되는 경우가 대부분입니다. 이런 경우 서로 다른 DB간 FK 설정 자체가 가능하지 않기 때문에 MSA에서는 서로 다른 DB간 외래키 이용이 불가능합니다. 이런 경우에는 어쩔 수 없이(?) 데이터 무결성을 위해서는 이벤트 기반 비동기 처리를 활용해 어플리케이션 레벨에서 관리가 필요합니다.

 

 


마무리

결국 외래키를 사용하고 말고는 정답이 없는 것 같습니다. 각 서비스 상황에 맞는 적절한 방식을 채택하는 것이 좋을 것 같습니다. 만약 설계가 탄탄하거나 데이터의 정합성이 중요한 경우 외래키를 사용하는 것이 더 좋을 것 같고, 추후에 데이터베이스 구조가 수정될 확률이 높은 스타트업이나 데이터의 정합성보다는 속도가 중요한 경우 외래키를 사용하지 않는 것이 더 좋을 것 같습니다.

 

 

참고 자료

 

외래키를 사용하지 않은 DB 기반 서비스 개발 | OKKY

최근 CQRS, GitOps, Cloud Native 방식등이 대두되고, 철저한 정합성 보다는 다른 이득이 더 중요하다고 판단하는 많은 서비스사에서 외래키를 사용하는 것을 지양하는 방식으로 개발 되고 있습니다.

okky.kr