TIL

8.10 외래 키

CREATE TABLE parent (
	id INT NOT NULL,
	fd VARCHAR(100) NOT NULL, 
	PRIMARY KEY(id)
) ENGINE=InnoDB;

CREATE TABLE child (
	id INT NOT NULL,
	parent_id INT DEFAULT NULL,
	fd VARCHAR(100) DEFAULT NULL,
	PRIMARY KEY(id),
	CONSTRAINT child_ibfk_1 FOREIGN KEY(parent_id) 
		REFERENCES parent(id) ON DELETE CASCADE
) ENGINE=InnoDB

8.10.1 자식 테이블의 변경이 대기하는 경우

작업 번호 커넥션-1 커넥션-2
1 BEGIN;  
2 UPDATE parent set fd=’chaged-2’ WHERE id=2;  
3   BEGIN;
4   UPDATE child SET parent_id=2 WHERE id=100;
5 ROLLBACK  
6   Qeury OK, 1 row affected (3.04 sec)
  1. 1번 커넥션이 먼저 트랜잭션을 시작하고 id=2인 parent에 대해 쓰기 잠금을 획득한다.
  2. 1번 커넥션이 parent 2번에 대해 쓰기 잠금을 가지고 있으므로 커넥션 2에서는 자식 테이볼 child의 외래키(parent_id)를 2로 변경하는 작업을 수행할 수 없어 기다리게 된다.
  3. 커넥션 1이 잠금을 해제한 후에야 커넥션 2의 쿼리가 정상적으로 수행된다.

8.10.2 부모 테이블의 변경 작업이 대기하는 경우

작업 번호 커넥션-1 커넥션-2
1 BEGIN;  
2 UPDATE child set fd=’chaged-100’ WHERE id=100;  
3   BEGIN;
4   DELETE FROM parent WHERE id=1;
5 ROLLBACK  
6   Qeury OK, 1 row affected (6.09 sec)

데이터베이스에 외래 키를 생성할 때 이러한 잠금 경합을 고려해 모델링하는 것이 좋다. 자식이 추가될 때 부모가 있는지 확인하는 등의 작업은 읽기 잠금을 유발하고 그만큼 잠금이 다른 테이블로 확장되어 전체적인 동시성 처리에 영향을 미친다.