메인 콘텐츠로 건너뛰기

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples on this page work on VillageSQL. Install Now →
외래 키는 두 테이블 사이의 관계를 강제하는 제약 조건입니다. 한 테이블 열의 값이 다른 테이블에 존재함을 보장하고, 참조된 행이 삭제되거나 갱신될 때 무슨 일이 일어나는지 정의합니다.

외래 키 정의하기

제약 조건 이름(fk_orders_customer)은 선택 사항이지만 포함할 가치가 있습니다 — 오류 메시지에 나타나고 ALTER TABLE 작업을 쉽게 만듭니다. 외래 키에는 InnoDB가 필요합니다 — MyISAM은 조용히 무시합니다.

참조 동작

ON DELETE와 ON UPDATE 절은 참조된 부모 행이 삭제되거나 갱신될 때 자식 행에 무슨 일이 일어나는지 정의합니다. SET DEFAULT는 SQL 표준의 일부입니다. InnoDB는 불평 없이 구문을 받아들이지만 구현하지는 않습니다 — 런타임에는 RESTRICT와 정확히 같게 동작합니다(ERROR 1451). 사용하지 마세요: 이름이 암시하는 것과 정반대로 조용히 동작합니다. **DELETE 시 CASCADE**는 편리하지만 위험합니다. 고객을 삭제하면 그 고객의 모든 주문이 자동으로 삭제됩니다 — 오류도 경고도 없습니다. 종속 행이 부모 없이는 정말로 의미가 없을 때(예: 주문 없는 주문 품목)만 사용하세요. **RESTRICT**가 더 안전한 기본값입니다 — 애플리케이션이 삭제를 명시적으로 처리하도록 강제하여 우발적인 데이터 손실을 막습니다.

필수 인덱스

MySQL은 외래 키 열에 인덱스를 요구합니다. 인덱스가 없으면 InnoDB가 자동으로 만듭니다.
이 인덱스가 외래 키 검사를 빠르게 만드는 것입니다 — 없으면 모든 INSERT나 DELETE에 전체 테이블 스캔이 필요합니다. FK 열에 대한 JOIN 쿼리도 빠르게 하므로, 명시적인 FK 제약 조건을 사용하지 않더라도 일대다 관계에서는 외래 키 열에 항상 인덱스를 만들어야 합니다.

외래 키 검사 확인 및 비활성화

대량 데이터 로드 중에는 외래 키 검사가 모든 삽입을 느리게 합니다. 일시적으로 비활성화하세요:
중요: 검사를 비활성화하면 고아 행을 삽입할 수 있습니다. 검사를 다시 활성화해도 기존 데이터를 소급하여 검증하지 않습니다. 검사를 끈 채로 데이터를 로드했다면, 검사를 다시 켜기 전에 참조 무결성을 수동으로 검증하세요.

기존 외래 키 보기

자주 묻는 질문

외래 키가 성능을 해치나요?

자식 테이블에 대한 모든 INSERT는 부모 테이블에 대한 검사(인덱스 조회)를 촉발합니다. 부모 테이블에서의 모든 DELETE는 자식 행에 대한 검사를 촉발합니다. 처리량이 높은 테이블에서는 이 검사들이 쌓입니다. 쓰기 처리량을 우선하는 팀은 대신 애플리케이션 계층에서 참조 무결성을 강제하는 경우가 많습니다. 어느 선택도 보편적으로 옳지는 않습니다 — 트레이드오프는 데이터베이스 수준의 안전성과 쓰기 성능 사이에 있습니다.

기존 테이블에 외래 키를 추가할 수 있나요?

예, ALTER TABLE로 가능합니다:
orders의 기존 행에 customers에 존재하지 않는 customer_id 값이 있으면 ALTER TABLE이 실패합니다. 먼저 데이터를 고치세요.

MySQL은 왜 외래 키에 대해 인덱스를 자동으로 만드나요?

InnoDB는 부모 행이 삭제되거나 갱신될 때 자식 행을 빠르게 검사해야 합니다. FK 열에 인덱스가 없으면 그 검사에 자식 테이블의 전체 테이블 스캔이 필요합니다. 자동 생성된 인덱스가 그것을 막습니다. 먼저 (의미 있는 이름으로) 자체 인덱스를 만들면 InnoDB는 두 번째 인덱스를 만드는 대신 그것을 사용합니다.

문제 해결

함께 보기