데이터베이스를 마지막 방어선으로
앱 검사는 친절한 오류를 만드는 데 좋지만 모든 쓰기 경로를 통제하지는 못해. 마이그레이션, 관리 스크립트, 다른 서비스가 우회할 수 있어. 절대로 깨지면 안 되는 규칙은 제약으로 데이터베이스에 새겨야 해.
UNIQUE는 중복을 막아
이메일이나 상품 코드처럼 같은 값이 둘 존재하면 안 되는 열에 써. 여러 열을 묶어 “사용자 1명은 한 상품에 리뷰를 하나만 남길 수 있다” 같은 범위의 고유성도 표현할 수 있어. NULL 처리 방식은 요구에 맞게 확인해야 해.
CHECK는 행 안의 논리를 검사해
가격이 0 이상인지, 할인율이 50 이하인지처럼 한 행의 불리언 조건을 강제해. 다른 행이나 시간에 따라 달라지는 규칙을 억지로 넣기보다 트리거나 별도 모델을 검토해.
EXCLUDE는 서로 겹치지 못하게 해
UNIQUE가 같은 값만 막는다면 EXCLUDE는 범위의 겹침처럼 연산 결과가 충돌하는 조합을 막아. 회의실 예약이나 유효 기간에 특히 강해. GiST 색인과 필요한 연산자 클래스를 이용해 “같은 자원에서 시간이 조금이라도 겹치면 안 된다”를 한 제약으로 표현할 수 있어.