ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 외래키(foreign key)를 쓰지 않는 이유
    DB 2023. 7. 22. 01:07

    오늘 일을 하며 DB를 짜던 도중 외래키를 쓰지 않는 것이 좋다는 선임분의 말을 들었다.

    이때까지 식별관계, 비식별관계 따져가며 테이블과 테이블 간의 접점을 위해 외래키를 잘 설정해주려고 노력했는데

    왜인지 의아했다. 하지만 실제로 외래키를 설정하게 되면 제약사항이 많아져서 그렇다고 한다.

    가령 cascade 설정으로 인해 A테이블을 삭제하면 B테이블이 삭제되거나, A를 수정하기 위해선 B까지 수정해야하는 경우들이 있다.

     

    외래키에 대한 이해를 위해 간단한 예시를 첨부했다.

     

    수강하는 주체인 학생과 그 대상인 강의, 그리고 그 행위를 나타내는 등록이 있다. 누가 어떤 강의를 듣는지 알기 위해 위와 같이 외래키로 테이블들을 이어주었다. 참고로 이들은 식별관계이다

    cf)

     

    식별관계:  어떤 테이블 (Student와 Lecture 테이블, 부모테이블)의 기본키(student_id, lecture_id)를

    다른 테이블(Registration 테이블, 자식테이블)에서 기본키로 사용하는 경우,

    이 경우 부모테이블에 데이터가 존재하지 않으면 자식 테이블에도 데이터가 존재할 수 없다.

    ('학생'이 '강의'를 신청하는 행위가 등록이니 그럴 수 밖에 없다)

    또 다른 예시로 게시글과 유저테이블이 있다고 가정할 때 어느 한 게시글에는 반드시 그 작성자가 있을 것이다.

    즉, 작성자인 유저가 없다면 게시글도 존재할 수 없는 것이다. 이런 경우 아래와 같이 테이블의 컬럼이 구성될 것이다.

    게시글_id 유저_id 게시글 관련 속성...
    1 1 블라블라...

     

     

    비식별관계: 한 테이블의 기본키를 다른 테이블의 외래키로 사용하는 경우,

    이 경우 부모테이블에 데이터가 존재하지 않아도 자식 테이블에 데이터를 생성할 수 있는 경우를 말한다.

    자동차와 타이어를 예로 들자면,

    보통 바퀴는 자동차에 사용되니 (하지만 자동차가 존재해야만 타이어가 존재하는 것 까지는 아니다.)

    사용되는 혹은 사용될 자동차가 무엇인지 알기 위해 자동차의 id를 외래키로 참조할 수 있다.

    그럴 경우 타이어 테이블의 모습은 아래와 같을 것이다.

    자동차_id 타이어_id 타이어 관련 속성...
    1 1 블라블라...
    1 2 Something

    (외래키가 비식별관계에만 쓰이는 개념이라는 것은 아니다. 식별관계의 핵심은 어디까지나 자식테이블 내 행의 존재가 부모테이블의 행에 의존한다는 것이다. 외래키는 기본적으로 부모 테이블의 기본키를 참조해서 가져온 자식테이블 내의 키를 말한다.)

     

    다시 본론으로 돌아와서

     

    외래키는 왜 사용하는 것일까?

    1. 데이터 정합성: 데이터 정합성은 Data Consistency, 즉 데이터들간의 일치를 말한다. 외래키가 설정되어 있지 않아 제약이 없다면 DB를 사용하는 사람이 임의로 데이터를 바꿀 수도 있다. 또, 수동으로 바꾸진 않았지만 복잡한 구조의 프로젝트를 하며 코드를 짠다면 테이블 간 관련된 데이터 중 일부를 빠뜨리고 변경할 수도 있는 것이다. 외래키를 설정해둔다면 테이블 간의 연관성에 대해 더욱 쉽게 알 수 있고 설정에 따라 하나만 바꾸는 것을 방지할 수 있다.

     

    2. 테이블 간의 구조 파악 용이: 외래키는 보통 두 테이블 간의 연관관계를 명시적으로 보여준다. 이것이 없다면 추후 자기자신 또는 다른 개발자가 구조를 보았을 때 단번에 파악하기 쉽지 않을 것이다. 구조가 복잡한데 ERD라도 역으로 그려야 한다면 더욱 힘들 것이다.

     

    외래키를 쓰지 않는 것이 좋은 이유는 무엇일까?

    1. 추가 연산으로 인한 성능 저하 유발: 외래키를 사용하게 되면 자식테이블에 연산시 기본적으로 참조하고 있는 부모테이블의 행도 검사하게 된다. 가령 강의 테이블에 Insert할 때 학생 테이블에 특정 학생이 존재하는 지 추가로 검사하는 것, 또 ON DELETE CASCADE같은 것을 설정해놓았다면 부모테이블(학생) 내 행을 삭제 시 자식 테이블(강의)의  행도 삭제되는 추가 연산이 발생한다.

     

    2. 개발에 제약 발생 및 용이성 저하: 제약 조건으로 인해 개발이 불편할 수 있다. 예를 들어 외래키가 설정되어있으면 ON DELETE CASCADE를 설정하기 전까진 부모테이블(학생)의 데이터를 삭제할 수 없다. 자식테이블에 묶여 있어 자식테이블(강의)의 행을 먼저 지운 후에 삭제가 가능하다. 생성 역시 마찬가지다. 학생 테이블의 데이터가 있어야 강의 테이블의 데이터를 생성할 수 있다.

     

    이에 대한 여러 논의들이 있지만 결국 성능데이터 무결성/정합성, 이들 중 어떤 것을 더 우선시하냐의 차이로 보인다.

    정답보단 그때 그때 목적에 따라 다르게 설정할 것이다.

     

    Plus) 만약 외래키를 쓰지 않는 것을 생각한다면 두 테이블 간 연관성은 어떻게 나타낼 수 있을까?

    게시글과 작성자라는 예시로 본다면 게시글에 Insert를 진행할 때 서버 측 코드에서 작성자에 해당 유저id를 주면 되는 것이다.

     

     

     

    출처:

    https://deveric.tistory.com/108

    https://stackoverflow.com/questions/762937/whats-the-difference-between-identifying-and-non-identifying-relationships

    Chat GPT

    https://valuefactory.tistory.com/1128

    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://juns-life.tistory.com/entry/DB-%EC%99%B8%EB%9E%98%ED%82%A4-foreign-key-%EC%82%AC%EC%9A%A9%EC%9D%84-%ED%95%98%EB%8A%94%EA%B2%8C-%EC%A2%8B%EC%9D%84%EA%B9%8C

     

    'DB' 카테고리의 다른 글

    Read DB(SELECT), Write DB(UPDATE, DELETE, INSERT)  (0) 2023.09.04
    DB 성능차이에 대한 Tips  (0) 2023.07.29
    varchar와 nvarchar의 차이  (0) 2023.07.21
Designed by Tistory.