Foreign Key

박시시·2023년 1월 17일
0

DB

목록 보기
1/1

foreign key 사용이유

foreign key를 사용하는 이유는 참조 무결성을 위해서이다. 연관관계에 있는 테이블에서, 외래키로 지정된 컬럼 데이터가 부모의 기본키 외 다른 값을 가질 수 없게 하여 외래키 컬럼에 저장될 수 있는 데이터를 제어하게 된다.
예를 들어, 유저, 주문 테이블이 있고 주문 테이블에 foreign key로 유저의 primary key를 갖고 있다 하면, 아직 가입 안된 유저 id로 주문테이블에 데이터를 넣으려하면 에러를 발생시켜 해당 데이터 삽입을 막는다. 이를 통해 주문 테이블 내에서 참조하는 값이 존재한다는 것을 보장할 수 있다. 즉 참조하는 테이블의 무결성을 높여주게 된다.

실무에서 foreign key 사용안하는 이유

성능 오버헤드

  • Insert/Update/delete 시 데이터의 정합성을 따져봐야 하기에 부모 테이블을 체크하는 등의 추가 작업이 진행된다(조사해본 결과 이 부분에서의 성능 영향은 미미하다고 한다).

관리포인트 증가

  • 테스트 등 진행시에 부모 row없이 자식 테이블 테스트만 하는 것이 불가능하다.
  • 트랜잭션 안에서 부모-자식 테이블 관계에 따라 작업 순서가 필요하다.
  • 규모가 증가함에 따라 데이터베이스의 설계도 조금씩 달라지는데 이 경우 참조무결성으로 인해 더 큰 수정개발을 불러 일으킬 수도 있다.
  • 실수로 데이터 변경하거나 지웠는데 연관관계에 있는 다른 테이블에까지 영향이 미치게 된다.

lock이 여러 테이블로 전파 -> 데드락 발생 가능성 생김

Transaction1Transaction2
beginbegin
insert into child(id, p_id) value (1, 1);
update parent set name="test1" where id = 1;
update parent set name="test2" where id = 1;
deadlock 발생

위의 표에 대한 설명은 아래와 같다.

트랜잭션 1에서 아래 쿼리와 같이 자식테이블에 parent_id를 1로 해서 인서트한다고 해보면
insert into child(id, p_id) value (1, 1);

이때 parent 테이블의 id 1번 로우에 slock이 걸린다.

트랜잭션 2 에서
update parent set name="test1" where id = 1;
위의 쿼리를 실행하면 xlock을 획득 시도하나 slock으로 인해 대기상태 들어간다.

트랜잭션 1 에서
update parent set name="test2" where id = 1;
위의 쿼리를 날린다 해보면, 이 경우 xlock을 획득하려하나 트랜잭션2의 xlock으로 대기에 들어가 결국 데드락이 발생한다.

즉 foreign key으로 인해 락이 다른 테이블로 전파되어 데드락 발생 가능성이 생긴다.

foreign key 컬럼에 인덱스를 반드시 걸어 조회 속도를 높이는 방법으로 최대한 데드락 발생 가능성을 낮춰야 한다.

객체지향적 접근

참조무결성을 db로 풀어야 할까?
참조무결성을 db 레이어에서 정의하게 되면 애플리케이션 레이어가 db를 따라가게 된다. db가 분리될 가능성도, 변경될 가능성도 있다고 할 때, db의 변경이 애플리케이션 레이어에까지 영향을 미칠 수 있다.
무결성이란 관심사가 애플리케이션 레이어에서의 책임, 관심사로 판단될 경우 애플리케이션 내에서 풀고 db에의 의존성을 덜어낼 수 있을 것이다.

물론 참조무결성이 중요하고 cascade, 즉 영속성전이 역시도 필요할 경우에는 당연히 foreign key를 사용해야 한다. foreign key가 좋다 나쁘다를 따지고 싶진 않다. 사실 데이터 무결성을 위해선 꼭 필요한 제약사항이기도 하다. 하지만 위와 같은 이유들로 인해 애플리케이션 단에서 무결성 관리를 철저히 하고 데드락 이슈를 줄일 수 있는 방향으로 서비스를 운영하기도 한다.

foreign key 사용안할 시 단점

데이터 무결성이 깨질 수 있다. 그러므로 애플리케이션 레벨에서 최대한 신경써가며 관리하여 최대한 데이터 무결성을 지킬 수 있도록 많은 노력을 기울여야 한다.

0개의 댓글