PostgreSQL Trigger로 본 테이블 updated_at 갱신 자동화하기

순덕·2025년 4월 23일
0
post-thumbnail

문제 인식

현재 진행중인 학회 프로젝트에서, 앱 개발 쪽 요구사항이 새로 들어왔다.

앱에서는 도감 데이터를 일괄적으로 서버로부터 제공받아 캐싱해 사용하고, 주기적으로 해당 데이터에서 변경된 부분만 확인해 받아오려고 합니다.

그럼 서버 쪽에서는
1. 도감 데이터를 전체 제공하는 API와,
2. 특정 시각 이후 갱신된 데이터만 확인해 제공하는 API
를 제공할 필요가 있다.

이때 문제는 2번, 특정 시각 이후 갱신된 데이터를 확인하는 것이다.
언뜻 보면 "updated_at 필드만 보면 되지 않을까?" 라고 생각할 수 있지만, 문제는 관련 데이터가 여러 테이블에 걸쳐 있다는 것이다.

구체적으로는 본 테이블(bird)에 bird_habitat, bird_image, bird_residency라는 서브 테이블들이 연결된 상황.

해결 방안 탐색

❓ 처음 떠올린 방안: 서브 테이블들 JOIN해서 확인해야 하나?

이 방법은 일단 어렵다고 판단했다. 이유는 첫번째, 각 테이블마다 created_at, updated_at, deleted_at 존재 여부가 서로 다르고, 이 문제를 해결하기 위해서 일괄적으로 그것들을 테이블마다 붙이는 것은 배보다 배꼽이 더 큰 격이라고 생각했다. 이거 하나 때문에 모든 관련 테이블을 Soft Delete로 처리하라니! 현실적으로 비효율적이다.
두번째, 성능적으로도 비효율적이다. 서브 테이블들은 모두 본 테이블에 대해 1:N으로 연결되어 있다. 이들 각각 JOIN시켜서 하나하나 확인하고 있자니, 그것도 모든 도감 데이터에 대해서!
아무래도 다른 방법이 필요했다.

💡 2번째 방안: 본 테이블의 updated_at 하나가 관련 테이블들의 생성/수정/삭제를 전부 반영할 수 있다면?

이거 괜찮았다. 예를 들어 bird_habitat 테이블에서 관련 데이터가 생성/수정/삭제될 경우마다 bird.updated_at을 갱신하는 것이다. 그러면 쿼리도 간단해지고 효율적이다.

🤔 하지만 어떻게 하지?

✅ 이럴 때 쓰는 게 Trigger

ChatGPT와의 대화를 통해 Trigger 개념에 대해 학습했다.
대화 전체는 여기서 볼 수 있다.

이 대화를 통해 배운 내용들을 요약하면:

  • 트리거는 특정 DML 이벤트(INSERT, UPDATE, DELETE)에 반응해 자동 실행된다.
  • PostgreSQL 트리거는 함수 형태로 작성되며 plpgsql 언어를 사용한다.
  • BEFORE 트리거는 DML 실행 전, AFTER 트리거는 실행 직후 (단, 커밋 전) 실행된다.
  • NEW 객체는 INSERT와 UPDATE 시 사용 가능하며, 변경 후 값을 담고 있다.
  • OLD 객체는 UPDATE와 DELETE 시 사용 가능하며, 변경 전 값을 담고 있다.
  • 트리거는 같은 테이블 내 필드뿐 아니라 다른 테이블도 명시적 쿼리로 수정할 수 있다.
  • 관계된 테이블의 변경으로 본 테이블의 updated_at을 갱신하려면 트리거 함수 내 UPDATE 쿼리를 써야 한다.
  • INSERT OR UPDATEAFTER 트리거로 처리하는 것이 일반적이다.
  • DELETEOLD를 사용해야 하므로 별도의 트리거로 관리하는 것이 명확하다.
  • 트리거는 트랜잭션 내부에서 실행되며, 커밋 전에 효과가 반영된다.

문제 해결

bird_habitat, bird_image, bird_residency 각각에 대해 다음 트리거들을 설정했다:

  • AFTER INSERT OR UPDATE: NEW.bird_id로 해당 birdupdated_at 갱신
  • AFTER DELETE: OLD.bird_id로 갱신

이제 도감 데이터 갱신 API는 단순히 bird.updated_at이 지난번 fetch한 시각보다 큰지만 확인하면 된다.

결과적으로, Trigger를 통해 관련 테이블의 변경을 본 테이블의 updated_at 하나로 일괄 추적할 수 있게 되었고, 클라이언트는 단순한 조건 비교만으로 변경된 데이터를 손쉽게 가져올 수 있게 되었다. 복잡한 연관 구조를 단순하게 관리하는 실용적인 해결책이었다!

profile
soonduck dreams

0개의 댓글