Post

데이터베이스 관계키(FK) 는 꼭 사용해야 할까?

데이터 무결성을 위해 필수적인 Foreign Key(관계키), 생성해야 할까요, 말아야 할까요? FK의 장점(무결성 보장, CASCADE)과 단점(제약검사 성능 저하)을 분석하고, 대규모 트래픽 시스템에서 ORM 레벨 논리적 관계키로 전환하는 최적의 데이터베이스 설계 전략을 제시합니다.

데이터베이스 관계키(FK) 는 꼭 사용해야 할까?

데이터 관계키(Foreign key, FK) 는 테이블의 무결성을 위해 사용됩니다. 무결성이라 함은 테이블간 연결된 데이터가 얼마나 신뢰할 수 있는지를 나타내며 관계키를 생성하면 테이블간 데이터는 신뢰할 수 있다고 판단합니다.


관계키를 생성하면 좋은 점

1. 무결성 보장

잘못 된 참조를 원천 차단합니다. 데이터 생성시 참조할 데이터가 해당 테이블에 존재하는 검사하기 때문에 존재하지 않는 데이터를 생성하지 못합니다.

2. 테이블 문서화 용이

MySQL Workbench 와 같은 데이터베이스 툴을 사용한다면 테이블간 관계를 다이어그램(ERD)를 시각적으로 자동으로 표현해주기 때문에 새로운 멤버에게 도메인 중심으로 인수인계가 용이합니다.

3. ON DELETE, ON UPDATE 활용 가능

  • ON DELETE CASCADE : 참조된 데이터 삭제시 자동 삭제
  • ON DELETE SET NULL : 참조된 데이터 삭제시 자동 NULL 변경
  • ON UPDATE CASCADE : 참조 키 값 변경시 자동 변경

위 기능은 시스템 유지보수 측면에서 개발자에게 편리함을 제공하기 때문에 많이 사용 됩니다. 데이터 삭제시 관련된 데이터를 모두 삭제하는 코드 혹은 쿼리를 작성 할 필요가 없기 때문에 쓰레기 데이터가 생성되는 걸 방지 할 수 있습니다.

4. JOIN(조인) 사용시 성능 힌트 제공

이 부분은 최근 공부하면서 알게 된 부분입니다. MySQL에서는 크게 성능이 개선되지 않지만 PostgreSQL, Oracle 등 데이터베이스에서는 쿼리 작성시 쿼리 최적화 힌트로 사용합니다. 직접 테스트를 해본적은 없지만 알아두면 좋을 것 같습니다.

5. 데이터 마이그레이션 데이터 정합성 검증

서비스를 운영하다 보면 간혹 데이터 마이그레이션을 할 때가 있습니다. 이 때 누락된 데이터 혹은 잘못된 데이터를 데이터베이스 단에서 쉽게 찾을 수 있습니다. 마이그레이션 과정에서 존재하지 않는 참조값을 넣게 되면 에러가 발생하여 데이터 정합성 측면에서 도움을 받을 수 있습니다.


관계키의 단점

1. 제약검사 비용 발생

데이터 생성/삭제/수정시 참조된 데이터가 존재하는지 데이터베이스 내부적으로 검사하게 됩니다. 대규모 트래픽에서는 참조 제약 검사가 성능 저하로 이어질 수 있습니다.

개인적으로 참조 제약 검사로인한 성능 저하는 시스템에 큰 부분을 차지 않다고 생각합니다. 만약 너무 많은 관계키가 생성되어 있다면 서비스코드 개선 및 테이블 정규화를 통해 개선하는 것이 더 효율적이라고 생각합니다. 이렇게 했는데도 개선이 안된다면 관계키를 제거해보는 것이 좋다고 생각합니다.

2. 데이터 마이그레이션 복잡도 향상

데이터 정규화 혹은 데이터베이스 개선, 타 시스템으로 이관 등의 이유로 데이터 마이그레이션을 하게 됩니다. 이 때 관계키가 있을 때 이관 순서를 꼭 정해야 합니다. 순서를 정하지 않고 마이그레이션을 시도하면 참조 제약 검사로 인해 실패하게 됩니다.

마이그레이션 할 때에는 이관 할 시스템에 관계키는 제거 후 마이그레이션이 완료 되면 관계키를 다시 생성하는 것을 추천합니다. 테이블이 수백,수천개인 경우 순서를 정하는건 시간적으로 불가능에 가까울 수 있습니다.


마무리

관계키는 생성하는 것이 좋을 수 있고 제거하는 것이 좋을 수 있습니다. 요즘은 ORM 을 많이 사용하기 때문에 ORM 레벨에서 논리적 관계키를 설정해서 사용해도 어느정도 만족스러운 결과를 얻을 수 있기 때문입니다.

결국 선택은 개발자에게 있지만 제가 시스템을 개발한다면 초기 시스템은 관계키를 생성해서 데이터 무결성을 보장받을 수 있도록 설계하고 엄청난 트래픽을 견뎌야 하는 시스템이라면 관계키를 제거하고 ORM 레벨에서 논리적 관계키를 설정하여 디비의 성능 저하를 개선 할 것 같습니다.

실제 과거 핵심 테이블을 제외한 일부 테이블의 관계키를 제거하고 ORM 레벨에서 논리적 관계키로 관리 했던 경험를 떠올리면 큰 문제는 발생하지 않았던 경험이 떠오르네요. 서비스로직만 잘 동작하고 코드변경이 적다면 관계키는 없어도 된다고 생각합니다.

This post is licensed under CC BY 4.0 by the author.