-
SQL AntiPatterns - Keyless Entry카테고리 없음 2025. 3. 2. 23:08
관계형 데이터베이스는 테이블 자체에 대한 설정도 중요하지만 테이블 사이의 "관계" 도 중요한 부분을 차지한다.
"참조 무결성" 은 이런 데이터베이스를 디자인하고 관련된 연산을 수행할 때 핵심적으로 동작해서 이런 부분에 도움을 준다.
예를 들어, foreign key 제약을 선언하면 해당 컬럼의 값은 다른 테이블의 primary key 혹은 unique key 로 존재해야 한다는 제약사항을 지킬 수 있도록 도와준다.

참조무결성을 사용하지 않는 이유
참조 무결성이 도움을 주긴 하지만 몇몇 사람들은 사용을 권하지 않는 경우가 있는데 그 때 언급되는 이유는 다음과 같은 것들이 있다.
- 데이터를 수동으로 갱신할 때 참조 무결성 제약에 위반되는 경우가 있다.
- 성능에 안좋은 영향을 준다.
예를 들어 개발 초기 단계에는 스키마에 변동이 자주 생기곤 하는데 이 때 제약조건에 걸려 불가능한 경우가 생길 수 있다. 또한 장애 대응을 빠르게 하기 위해 DB에 직접 접근하여 수동으로 데이터를 조작해야 하는 경우가 생길 수 있는데 해당 동작이 막혀있다면 빠르게 대응하지 못할 수도 있다.
참조 무결성을 사용하지 않을 때의 대응
만약 외래키가 동작하는 방식 그대로를 애플리케이션 로직으로 잘 구현할 수 있다면 테이블에 외래키 제약을 걸어둘 필요는 없다고 생각할 수 있다. 예를 들어 새로운 row 를 추가하고자 할 때 외래키로 설정하고 싶은 컬럼의 값이 참조하는 테이블에 존재하는지 확인하는 로직을 작성해볼 수 있다.
물론 이런 방법이 잘 동작하기 위해서는 로직이 늘 잘 짜여져 있다는 전제조건이 있어야 하고 만약 다른 팀에서 이를 사용하고자 할 때에도 적절한 가이드를 제공해야 한다.
또한 Lock 을 적절히 사용하지 않으면 데이터가 추가되는 시점과 조회되는 시점에 발생하는 차이로 인해 로직을 정확하게 작성했더라도 잘못된 데이터가 테이블에 들어갈 수 있는 확률도 존재한다.
잘못된 데이터가 들어가는 경우를 위해서 이를 확인하고 정정해주는 스크립트를 작성해놓고 주기적으로 실행하는 방법을 생각해볼수도 있다. 이 때는 어떤 주기로 스크립트를 실행해야 할 지, 데이터가 많아졌을 때 스크립트를 돌림으로써 서비스에 어떠한 영향을 주게 될 지를 고민해 보아야 한다.
외래키 제약이 방해가 되는 경우
A ( id int, status string foreign key (status) references B(status) ) B ( id int, status string )A.status 가 B.status 를 외래키로 참조하는 경우를 생각해보자.
만약 status의 값을 INVALID 로 변경하고 싶을 때 다음과 같은 상황을 마주하게 된다.
UPDATE B SET status = 'INVALID' WHERE status = 'TEST' UPDATE A SET status = 'INVALID' WHERE status = 'TEST'위 두 쿼리는 동시에 적용되어야지만 참조 무결성을 깨뜨리지 않고 갱신될 수 있다. 만약 이를 각각 실행하게 된다면 각 쿼리는 무결성을 해치기 때문에 에러가 발생하며 해당 작업을 수행할 수 없게 된다.
해결 방법
CREATE TABLE A ( status VARCHAR(20) NOT NULL DEFAULT 'NEW' foreign key (status) references B(status) on update cascade on delete set default )외래키 제약을 걸 때 cascading update 를 적용하면 위와 같은 문제에서 벗어날 수 있다.
ON UPDATE CASCADE 는 B 테이블에 대한 갱신이 자동으로 A에 전파되게 된다.
이런 식으로 ON UPDATE, ON DELETE 를 외래키 제약에 추가하게 되면 cascading operation 이 발생했을 때 어떤 식으로 처리할 지를 직접 관여해서 설정할 수 있게 된다.
나의 생각
최근 프로젝트를 진행하면서 테이블을 설계해야 하는 경우가 많이 있었는데 그 때 매번 들었던 생각이 외래키 제약을 거는 것이 좋을지 아닐지에 대한 것이었다. 어떤 사람들은 거는게 좋다고 하고 다른 사람들은 앞서 말한 이유를 들면서 실제환경에서는 잘 걸지 않는다고 말하기도 해서 많이 헷갈렸다.
책을 읽고 난 다음에도 여전히 어떤 것이 더 나은 선택인가에 대한 의문이 완전히 해소되진 않았지만 그래도 각각의 선택에는 장단점이 있고 나름 단점을 상쇄할만한 장치들이 존재한다는 것을 알게 되었다.
현재 진행하는 프로젝트의 스키마도 계속해서 변경되고 있는데 이번에는 외래키 제약을 걸어서 활용해 보고자 한다. 현재는 파일을 많이 다루기도 하고 orphan data 가 생기면 사용되지 않는 파일이 스토리지를 계속해서 차지하게 되는 문제가 있을 것 같다는 생각이 든다.
시간이 흐른 뒤에 지금 나의 선택이 프로젝트에 어떤 영향을 주었는지를 되돌아보면서 외래키에 대한 선택이 어땠고 어떤 효과를 만들어냈는지를 되돌아 볼 수 있었으면 좋겠다.