Database

[SQL] SET FOREIGN_KEY_CHECKS와 외래키 제약조건

snape 2023. 3. 29. 10:26

Project Test를 진행하다가, 외래키와 관련된 에러를 마주했다.

결론적으로 해결은 매우 간단했다. 만약 바쁘다면 아래와 같이 명령어를 실행하면 된다. 

SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE TABLE $table_name;
SET FOREIGN_KEY_CHECKS = 1;

 

이제 에러를 마주했으니 원인과 그에 대한 이유를 세부적으로 알아보자.

 

외래키 제약 조건이란?

 외래키(Foreign Key) 제약조건은 관계형 데이터베이스에서 사용되는 제약조건 중 하나로, 테이블 간의 관계를 유지하기 위해 사용된다. 이에 따른 특성은 다음과 같다.

  • 참조 무결성 유지
    • 외래키제약조건을 사용하면, 참조된 테이블의 기본키 값과 일치하지 않는 값이 외래키로 저장되는 것을 방지하여 데이터의 무결성을 유지할 수 있다.
  • 관계 유지
    • 외래키 제약조건은 테이블 간의 관계를 유지할 수 있다. 예를 들어 주문 테이블과 상품 테이블이 있을 때, 주문 테이블의 상품 ID 컬럼이 상품 테이블의 ID 컬럼을 참조하는 외래키 제약조건을 설정하면, 주문 테이블에서 상품 ID 값을 변경하거나 삭제할 때 관련된 상품 행도함께 변경되거나 삭제된다.
  • 자동 연결
    • 외래키 제약조건을 설정하면 다른 테이블에서 데이터를 가져와서 새로운 레코드를 추가할 때, 자동으로 외래키 값을 연결해준다.
  • 성능 저하
    • 하지만 외래키 제약조건은 데이터를 추가, 수정, 삭제할 때 성능에 영향을 미칠 수 있다. 외래키 제약조건이 설정된 테이블에서 데이터를 추가, 수정, 삭제할 때는 참조된 테이블에서도 동시에 작업이 수행되어야 하기 때문이다.     

 

외래키 제약조건의 설정과 해제

위에서 해결 방법으로 SET FOREIGN_KEY_CHECKS를 사용했다. 다만 이 방법은 MySQL을 사용할 때 해결되는 방법으로 다른 DB에서는 아래와 같다.

--- MySQL 외래키 제약조건 체크 활성화
SET FOREIGN_KEY_CHECKS = 1;

--- MySQL 외래키 제약조건 체크 설정 비활성화
SET FOREIGN_KEY_CHECKS = 0;


--- Oracle 외래키 제약조건 설정 비활성화
ALTER TABLE table_name DISABLE CONSTRAINT constraint_name;


--- PostgreSQL 외래키 제약조건 비활성화
ALTER TABLE child_table DROP CONSTRAINT child_table_parent_table_fkey;

-- PostgreSQL 외래키 제약조건 활성화
ALTER TABLE child_table ADD CONSTRAINT child_table_parent_table_fkey
FOREIGN KEY (parent_id) REFERENCES parent_table(id)
ON UPDATE CASCADE ON DELETE CASCADE;

 

외래키 제약조건 변경의 위험성

외래키 제약조건을 직접적으로 변경하는 것은 권장되지 않는다. 외래키 제약조건은 데이터 무결성을 보장하기 위한 중요한 요소 중 하나이다. 이 제약조건이 설정되어 있으면 참조되는 다른 테이블의 데이터와의관계를 유지할 수 있으며, 데이터의 일관성을 보장할 수 있다.

그러나 외래키 제약조건을 직접적으로 변경하는 옵션을 사용하게 되면 데이터의 일관성을 보장하지 못하게 만들 수 있다. 예를 들어 참조되는 다른 테이블의 데이터가 삭제되었는데도 불구하고 외래키 제약조건을 무시하고 삭제를 진행하면, 데이터의 일관성이 깨지게 되는 것이다.

따라서 제약조건을 변경하였다면 필히 원래대로 설정해줘야 한다.

 

보다 안전한 방법은?

  1. Cascade 옵션 설정
  2. 수동으로 자식 엔티티를 먼저 삭제하거나 NULL로 변경 

Cascade 옵션을 사용하면 부모 엔티티를 삭제할 때 자식 엔티티도 함께 사용된다. 이 때 데이터베이스에서 참조 무결성을 유지하기 위해 자식 엔티티의 외래키 값이 자동으로 NULL 설정되거나, 참조된 다른 테이블에서 해당 레코드가 자동으로 삭제되지는 않는다.

참조된 다른 테이블에서 해당 레코드를 수동으로삭제하거나 외래키 값을 변경하는 작업은 데이터베이스에서 참조 무결성을 유지하기 위해 수행하는 작업이다. 이를 통해 부모-자식 간의 참조 관계가 무너지지 않도록 보장하며 데이터의 일관성과 무결성을 유지할 수 있다. 

 

Cascade의 옵션에는 어떤 것이 있나?

spring JPA에서 cascade의 옵션은 6가지 종류가 있다. 

  1. CascadeType.PERSIST
    • 부모 엔티티가 저장될 때, 자식 엔티티도 함께 저장된다.
    • 자식 엔티티를 영속화하려면 부모 엔티티가 먼저 저장되어 있어야 한다.
  2. CascadeType.MERGE
    • 부모 엔티티가 병합될 때, 자식 엔티티도 함께 병합된다.
    • 자식 엔티티를 병합하려면 부모 엔티티가 먼저 병합되어 있어야 한다.
  3. CascadeType.REMOVE
    • 부모 엔티티가 삭제될 때, 자식 엔티티도 함께 삭제된다.
    • 자식 엔티티를 삭제하려면 부모 엔티티가 먼저 삭제되어 있어야 한다.
  4. CascadeType.DETACH
    • 부모 엔티티가 준영속 상태로 전환될 때, 자식 엔티티도 함께 준영속 상태로 전환된다.
  5. CascadeType.REFRESH
    • 부모 엔티티가 리프레시될 때, 자식 엔티티도 함께 리프레시 된다.
  6. CascadeType.ALL
    • 모든 Cascade 작업을 포함하는 종합적인 옵션