최근 외래키에 대하여 질문을 받은적이 있다. 실무에서 잘 사용하지 않고 성능적인 이슈가 있다는건 어렴풋이 기억나는데 확신이 서지않아 정확하게 대답을 못한 일이 있었다. 오래되서 기억이 잘 안날수도 있겠지만 정확히 이해하지 않고 이때까지 관성적으로 사용한 기분이라 이번 기회에 제대로 알아봐야겠다.
내 기억 속 외래키..
학부생 시절 관계형 데이터베이스에 대해 배울때 외래키에 대해서 배웠었고 스키마 설정시 외래키도 지정했었던걸로 기억한다. 근데 막상 실무에 투입되어보니 외래키를 다들 쓰고있지 않았다.
보통 외래키를 사용함으로 인해 데이터 정합성 문제를 해결할수 있고 이로 인해 데이터 신뢰도가 높아질수 있을 것이다. 하지만 실무에선 이 외래키를 사용함으로 인해 얻는 장점보다 단점이 더 많아 보였기 때문에 외래키를 사용하지 않았을 것이다.
그리고 그때 내가 듣기론 외래키를 지정함으로 인해 CRUD 발생시 데이터 정합성을 위해 DBMS 에선 추가적인 쿼리를 실행시켜 외래키로 지정된 다른 테이블의 row 가 존재하는지 확인 하거나, 해당 row 가 삭제 되었을시 연관된 다른 테이블의 row들도 삭제(CASCADE ON DELETE)하는 등의 오버헤드가 발생하여 성능 부하 문제가 일어날수도 있기 때문에 사용하지 않는걸로 기억한다.
1. 외래키(foreign key)란?
2. 외래키를 사용하는 이유
3. 외래키를 사용하지 않는 이유
4. 결론
1. 외래키(foreign key)란?
부모 - 자식 테이블 관계를 맺어주고 스키마를 통해 각 테이블간의 연관 관계를 명시적으로 알수있다.
제약조건인 참조 무결성(referential integritiy)을 통해 데이터 정합성을 지킬수 있다.
2. 외래키를 사용하는 이유
- 외래키의 가장 큰 장점으로는 데이터가 일관되고 정합성이 지켜지는 것이다.
외래키 없이 데이터 정합성을 지키기 위해선 어플리케이션단에서 코드를 통해 이것을 지켜야 한다.
어플리케이션단 코드는 보통 협업을 하며 많은 사람들의 손을 거치게 되는데 시간이 지남에 따라 한계를 보일수밖에 없고 DB 클라이언트를 통해 직접 접근하여 수동으로 데이터를 바꾸는 경우도 있다. (이러면 안되는걸 알지만 편의를 위해 공공연히 발생 할 것이다. 그리고 DB 관리자를 제외한 개발자에겐 운영 DB 관련해선 READ-ONLY 계정만 주기도 한다.)
결국 외래키가 없는 상태에선 시간이 지날수록 데이터 정합성이 조금씩 깨지기 시작한다. - 스키마를 통해 각 테이블간의 관계를 명확히 알 수 있다.
DB 스키마를 분석하여 ERD를 자동으로 그려주는 툴을 통해 확인해보면 가시적으로 이를 확인 할 수 있다.
따로 외래키가 지정되어 있지 않은 경우 보통은 어플리케이션단 코드를 보며 파악하거나 문서(시간이 지남에 따라 현상태와 맞지 않을수도 있다)를 통해 파악해야 할 것이다.
그리고 만약 어플리케이션 코드에 ORM 이 사용되지 않았다면 코드에서도 테이블간 관계를 명시적으로 확인하기 더 힘들것이다. 결국 이는 인수자가 구조를 파악하기 어렵고 시간이 걸린다.
3. 외래키를 사용하지 않는 이유
- 추가적인 컴퓨팅 리소스 비용 (CPU cost 발생)
위에서도 말했듯이 외래키 관련 CRUD 발생시 데이터 정합성을 위해 DBMS 에선 추가적인 쿼리를 실행시켜 외래키로 지정된 다른 테이블의 row 가 존재하는지 확인 하거나 해당 row 가 삭제 되었을시,
연관된 다른 테이블의 row들도 삭제(CASCADE ON DELETE)하는 등의 오버헤드가 발생하여 성능 부하 문제가 일어날수도 있다는 우려가 있는데 알아보니 추가적인 오버헤드 비용이 그렇게 크진 않은것 같다.
link) 외래키가 Insert 속도에 영향을 끼치나요? - 기존 레거시 데이터의 정합성이 맞지 않다.
기존 데이터의 정합성이 맞지 않아 외래키를 추가 하려고 해도 제약조건에 걸려서 추가가 힘들다는 것 인데
이는 옵션을 통해 제약사항을 잠시 껐다가 다시 키는 방법을 통해 해결할수 있다고 한다. (Enable Novalidate 옵션)
- https://engineering-skcc.github.io/oracle%20tuning/foreign_key_%EC%97%86%EC%9D%B4_%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94_DB/ - 개발시 외래키가 있음으로 인해 불편하다.
외래키의 참조 무결성 제약사항으로 인해 부모 - 자식 관계에서 자식 테이블의 row를 추가 할시 자식이 외래키로 참조 하고있는 부모 테이블의 row 가 있어야 DML 작업이 가능하다.
하지만 테스트 데이터를 만들때 이러한 제약사항 때문에 개발자가 자유롭지 못하다는게 있는데 이 또한 외래키를 Deffered 옵션으로 만들면 해결 가능하다고 한다.
- https://engineering-skcc.github.io/oracle%20tuning/foreign_key_%EC%97%86%EC%9D%B4_%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94_DB/
4. 결론
글을 쓰다보니 기존 스키마에 외래키를 추가하는 방법 또는 써야하는 이유가 되버린 것 같긴하다.
개인적인 경험으론 오래된 서비스의 경우 데이터 정합성이 깨져있는 경우도 봤었기 때문에 인수인계받아 운영 하는 개발자 입장에선 난감하기도 하고 그 DB에 쌓인 데이터들에 대한 신뢰가 떨어지기도 한다.
결국 외래키를 이용해 데이터 정합성을 지키되 상황에 맞게 적용하여 쓰면 될 것 같다. 민감한 결제 데이터 같은 경우엔 처음 부터 외래키를 걸어놓아 데이터 정합성을 꼭 지켜야 할 것이고, 스타트업 같은 곳에선 요구사항이 시시때때로 변해 처음에 인덱스만 걸어놓았다가 나중에 외래키를 나중에 추가할수도 있을 것 같다. 그리고 구현 하는 기능에 따라 좀더 느슨하게 관리해도 된다면 외래키를 걸지 않을수도 있을거 같다.
(개발은 절대적인 답이 있기보단 항상 트레이드 오프를 비교해가며 상대적인 결정을 해야한다.)
참고자료
https://engineering-skcc.github.io/oracle%20tuning/foreign_key_%EC%97%86%EC%9D%B4_%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94_DB/
https://okky.kr/articles/586565
https://dataedo.com/blog/why-there-are-no-foreign-keys-in-your-database-referential-integrity-checks
https://www.brentozar.com/archive/2015/05/do-foreign-keys-matter-for-insert-speed/
https://www.quora.com/What-are-the-advantages-and-disadvantages-of-foreign-keys-in-database-design
'IT > DB' 카테고리의 다른 글
[MySQL] Character Set 불일치 문제 (0) | 2024.11.10 |
---|---|
[Mysql] 서비스 다운타임을 최소화할수 있는 테이블 스키마 업데이트 (0) | 2023.10.08 |
[DB] DB 인덱스에 대하여 (1) | 2022.11.01 |