MySQL에서 데이터 무결성을 유지하기 위해 가장 핵심적인 제약조건 중 하나는 FOREIGN KEY(외래 키)이다.
이 제약조건은 INSERT, UPDATE, DELETE 같은 DML(데이터 조작어) 명령어 실행 시 매우 중요한 역할을 한다.
하지만 잘못된 설정이나 이해 부족으로 인해 외래 키 에러를 자주 만나게 된다.

🧱 FOREIGN KEY란?
외래 키(Foreign Key)는 한 테이블의 컬럼이 다른 테이블의 기본 키(Primary Key) 또는 유니크 키를 참조하도록 강제하는 제약조건이다.
이 제약조건은 데이터 간의 관계(Relationship)를 표현하고, 데이터의 정합성(무결성)을 보장한다.
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
FOREIGN KEY (user_id) REFERENCES users(id)
);
위 예제에서 orders.user_id는 users.id를 참조하고 있다.
즉, users 테이블에 존재하지 않는 사용자의 주문을 추가할 수 없도록 막는다.
💥 DML 명령어에서 발생할 수 있는 외래 키 오류
1️⃣ INSERT 오류
INSERT INTO orders (id, user_id) VALUES (1, 999);
→ users 테이블에 id = 999가 없으면 foreign key constraint fails 에러가 발생한다.
2️⃣ UPDATE 오류
UPDATE orders SET user_id = 1234 WHERE id = 1;
→ user_id를 users에 존재하지 않는 값으로 바꾸면 외래 키 위반으로 실패한다.
3️⃣ DELETE 오류
DELETE FROM users WHERE id = 2;
→ 만약 orders 테이블에서 user_id = 2가 사용 중이면 삭제할 수 없으며 에러 발생
🔧 해결 방법: 외래 키 행동 옵션
외래 키 제약조건을 정의할 때 ON DELETE, ON UPDATE 옵션을 통해 연쇄 행동을 지정할 수 있다.
| 옵션 | 설명 |
| CASCADE | 참조된 키가 삭제/수정되면, 종속된 테이블의 데이터도 함께 삭제/수정됨 |
| SET NULL | 참조된 키가 삭제/수정되면, 외래 키를 NULL로 설정 |
| RESTRICT | 참조된 키가 사용 중이면, 삭제/수정 불가능 (기본값) |
| NO ACTION | RESTRICT와 같지만 트랜잭션 상황에 따라 동작 다름 |
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
→ 부모 테이블의 사용자가 삭제되면 관련 주문도 자동으로 삭제된다.
⚠️ 실무 주의사항
- ON DELETE CASCADE는 매우 강력하므로, 설계 시 주의가 필요하다. 실수로 전체 데이터가 삭제될 수 있다.
- SET NULL을 사용하려면 외래 키 컬럼이 NULL을 허용해야 한다.
- 외래 키가 여러 개 연결된 경우, 트랜잭션 충돌이 날 수 있으므로 트랜잭션 사용 시 순서에 주의해야 한다.
✍️ 실습 예제: 외래 키와 함께 사용하는 INSERT / DELETE
사용자 테이블
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50)
);
주문 테이블
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
예제 실행
INSERT INTO users (id, name) VALUES (1, 'Alice');
INSERT INTO orders (id, user_id) VALUES (100, 1);
DELETE FROM users WHERE id = 1;
→ Alice가 삭제되면서 orders 테이블의 주문도 함께 삭제된다. (CASCADE 효과)
🧠 FOREIGN_KEY_CHECKS로 제약 일시 해제
개발 환경에서 제약을 일시적으로 끄고 싶을 때 사용
SET foreign_key_checks = 0;
DELETE FROM users WHERE id = 1;
SET foreign_key_checks = 1;
주의: 실제 운영 환경에서는 사용 지양. 데이터 무결성이 깨질 수 있다.
📚 참고 자료
'DB' 카테고리의 다른 글
| [MySQL] 인덱스 종류 완전정복 (BTREE, HASH, FULLTEXT, SPATIAL)🧩 (0) | 2025.07.03 |
|---|---|
| [MySQL] 인덱스란? 개념과 필요한 이유 완벽 정리 🧠 (0) | 2025.07.03 |
| [MySQL] DML과 LOCK 동작 원리 및 충돌 해결 가이드 🔒 (0) | 2025.07.03 |
| [MySQL] DML과 트랜잭션 오토커밋 제어 완벽 정리 ⚙️ (0) | 2025.07.03 |
| [MySQL] 트리거로 DELETE 감지: BEFORE / AFTER 완벽 가이드 🗑️ (2) | 2025.07.03 |
| [MySQL] 트리거로 UPDATE 감지: BEFORE / AFTER 활용법 완전 정복 🛠️ (0) | 2025.07.03 |
| [MySQL] 트리거 BEFORE / AFTER INSERT 실무 활용법 🔄 (0) | 2025.07.03 |
| [MySQL] WITH CTE로 INSERT / UPDATE / DELETE 처리하는 실전 예제 모음 (0) | 2025.07.03 |