[DB] 외래키의 장점과 단점 및 논의

subutai·2021년 4월 8일
19

매일 CS

목록 보기
3/3

Foreign key

데이터베이스 개론을 들으면, 외래키는 테이블과 테이블간의 연관관계를 맺어주는
역할을 한다고 한다. 생각해보면 외래키의 여러가지 장점만 배우고,
예를들어 제약조건 생성, 테이블관의 명시적인 관계표출 등이 있다고 배웠고
당연히 테이블이 연관관계가 있을때 사용하는것이라고 생각했는데
실제로 사용되는 예를보면 오히려 외래키를 사용하지 않는것이 좋다는 의견이 많은 것 같다

데이터 무결성이라는 큰 장점이 있지만(referential integrity), 주로 성능때매 사용을 꺼려하는 것으로 보인다.

  1. 자식 테이블 INSERT 시에 부모 테이블이 존재하는지 확인해야하는 비용(CPU cost)

  2. 테이블 구조 변경시 고려사항이 많이 생김

  3. 테스트 데이터 만드는 것이 불편하다
    -> 이건 프로젝트 할 때마다 나도 많이 경험해보았다.

  4. 외래키가 잡혀있으면 실행계획 제어가 안 된다?

그런데 막상 조사해보니, 외래키를 사용하는것이 더 낫다는 의견이 조금 더 설득력 있다고 생각됐다

  1. 자식 테이블 DML 시에 부모 테이블이 존재하는지 확인해야하는 비용(CPU cost)
    -> 분명히 존재하는 오버헤드지만, OLTP에서 영향을 끼칠만한 오버헤드는 아니다
    그리고, FK를 사용하지 않으면 결국에 부모 테이블이 존재하는지 SELECT를 어플리케이션 단에서
    날려야하는데, 이렇게 사용하면 오버헤드는 오버헤드대로 더 커지고, referential integrity도
    안 지켜진다.
    대용량 디비에서는 외래키를 안쓰나요? 를 보면
    외래키 때문에 DB의 병목이 발생하여 떨어져서 떼고쓴다고 말하는 경우가 많다고하지만
    사실 그러한 DB 대부분이 외래키 문제가 아니라, 데이터베이스 설계 자체문제, 부적절한 인덱스인
    경우가 많다는 지적이 있다.
    개인적인 생각으로는, Data integrity 는 trade-off 대상이 아니지않나 생각이 든다.
    서비스 되는 DB에서 Data integrity 가 조금 어긋나도 상관없는 테이블의 예시가 전혀 떠오르지 않는다.

    또 드문 경우지만 PK가 UPDATE 대상이 되는경우(!) 자식 테이블에서 외래키를 인덱스로
    가지고 있다면 index scan으로 순식간에 찾을 수 있다

  1. 테이블 구조 변경시 고려사항이 많이 생김
    -> 이 부분은 Foreign Key 없이 구축하는 관계형 데이터베이스 시스템에 대한 생각 에서
    다양한 우회법이나 해결법을 많이 제시해주는데, Bulk insert 시에는 잠시 외래키 체크를 끈다던지 하는 방법들이다.

  2. 테스트 데이터를 만드는게 불편하다
    이거는 Foreign Key 없이 구축하는 관계형 데이터베이스 시스템에 대한 생각 이 링크에서 충분히 대안을 제시한다.

  3. 외래키가 잡혀있으면 실행계획 제어가 안 된다?
    실행계획은 옵티마이저에 의해서 생성되는데, 옵티마이저가 사용하는 옵티마이징 팩터는
    인덱스 구성이랑 적절한 SQL 이다.
    규칙기준 옵티마이저랑 비용기준 옵티마이저 모두 외래키와 관련된
    옵티마이징 팩터는 없다.

결론적으로, 정리해본 결과는 외래키를 사용하는것이 낫고 성능적인 문제는 없다고 볼 수 있다.
물론, Bulk INSERT/DELETE 시에는 분명히 외래키가 연산의 성능에 큰 영향을 미친다.
외래키를 성능문제 없이 잘 사용하기 위해서는 아래와 같이
1. 외래키 컬럼에 인덱스 달아주기
2. 부모 테이블의 PK가 변하지 않도록 디자인 하기
3. PK를 가능한한 인공키로 정하기

참고
What are the advantages and disadvantages of foreign keys in database design?
대용량 디비에서는 외래키를 안쓰나요?
Foreign Key 없이 구축하는 관계형 데이터베이스 시스템에 대한 생각
[펌][스크랩]FK 외래키의 사용, 필요성에 대한 도움글
외래키 쓰는 이유가 무엇인가요?
Does Foreign Key improve query performance?

SQL vs NoSQL

SQL 이란 이름은 원래 SEQUEL(Structured English Query Language) 이란 이름에서 SQL 로 줄어든것이다
여기서 왼쪽의 SQL 은 관계형 데이터베이스(RDBMS)이고. 관계형 DB란 테이블로 이루어져 있고
데이터를 컬럼, 로우를 이루는 하나 이상의 테이블로 정리하고, 고유키가 각 로우를 식별하는 특징이 있다.
데이터의 형식(schema)에 매우 엄격하며 많은 제한사항이 있는것이 특징이다. 예를 들어 레코드 삽입시
스키마와 맞지 않는 레코드의 삽입은 제한된다.

NoSQL 은 스키마의 개념이 없다. 따라서 삽입되는 레코드의 형식에 제한이 없다.
없던 컬럼이 추가될 수 도 있고 빠진채로 들어갈 수 도 있다. NoSQL이 나오게된 계기는
웹과 빅데이터가 발전하면서 관계형 데이터베이스에 몰리는 데이터가 엄청나게 많아지면서
성능의 한계를 경험하였기 때문이다.왜냐하면 RDBMS 는 테이블들의 관계를 JOIN을 사용하여
관계된 데이터들을 조직화하는 방식을 사용하기에, 관게된 테이블들이 함께 다닐수 밖에 없었고
결국, 수평적 확장 대신 수직적 확장을 할 수 밖에 없었으며. 아시다시피 수직적 확장은 매우 제한적이고
가성비가 좋지 않다.

반면에, NoSQL은 테이블들간의 관계나 제약조건에 자유롭기 때문에, 여러 NoSQL DB 클러스터를 운영하며
수평적인 확장을 쉽게 할 수 있는 장점이 있다.
물론 장점만 있는것은 당연히 아니다. CS의 대부분의 영역에서, 제한은 안정을 의미하고 자유는 불안정을 의미한다.
스키마가 바뀔 수 있기 때문에 일관성이 깨질 수 있으며, 시간이 지날수록 그때그때 필요한 온갖 컬럼이
추가된 끔찍한 모습이 될 수 있다. 자유로운 컬럼 추가는 한 두개일 때나 좋은게 아닐까?
또한, 암시적인 데이터타입은 있지만, 강제되지는 않기 때문에 데이터 타입 불일치가 발생할 수 있다.

결국엔 둘 중 누가 승자냐? 따질것이 아니라, RDBMS 보다 NoSQL이 적합한 영역에서는 NoSQL을 융통성 있게 쓰는것이 좋다

Transactional

스프링 컨테이너는 트랜잭션 범위의 영속성 컨텍스트 전략을 기본으로 사용!
-> 트랜잭션 범위 = 영속성 컨텍스트 생존 범위
같은 트랜잭션 안에서는 항상 같은 영속성 컨텍스트에 접근한다.

@Transactional 어노테이션을 쓰면 메소드 호출전에 스프링 트랜잭션 AOP가 동작한다.
이 AOP가 고맙게도 트랜잭션 커밋과 롤백을 해주기 때문에, JDBC 직접 만질때처럼 commit, rollback을
호출해주지 않아도 된다.

  1. 트랜잭션이 같으면 같은 영속성 컨텍스트를 사용한다
  2. 트랜잭션이 다르면 다른 영속성 컨텍스트를 사용한다
    -> 여러 스레드에서 동시에 요청이 와서 같은 엔티티 매니저를 사용해도 트랜잭션에 따라
    접근하는 영속성 컨텍스트가 다르다(스프링은 스레드마다 각 각 다른 트랜잭션을 할당)

0개의 댓글