INSERT·UPDATE·DELETE에 반응해 자동으로 실행되는 코드.
기본형
-- PostgreSQL: 함수를 만들고 트리거로 연결한다
CREATE OR REPLACE FUNCTION set_updated_at() RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER trg_member_updated
BEFORE UPDATE ON member
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
-- MySQL: 본문을 트리거에 직접 쓴다
CREATE TRIGGER trg_member_updated BEFORE UPDATE ON member
FOR EACH ROW SET NEW.updated_at = NOW();
BEFORE와 AFTER
- BEFORE — NEW 값을 고칠 수 있다 → 값 보정 · 정규화 · 검증
- AFTER — 이미 확정됐다 → 감사 로그 · 집계 갱신 · 다른 테이블 반영
잘 맞는 용도
-- 감사 로그 — 누가 무엇을 바꿨는지 빠짐없이 남긴다
CREATE TRIGGER trg_audit AFTER UPDATE ON account
FOR EACH ROW EXECUTE FUNCTION write_audit_log();
애플리케이션 경로가 여러 개여도 트리거는 반드시 실행된다. 감사·이력처럼 "절대 빠지면 안 되는" 일에 강하다.
왜 신중해야 하나
-
① 흐름이 코드에 안 보인다
- UPDATE 한 줄이 실제로 무엇을 하는지 애플리케이션 코드만 봐서는 알 수 없다
- 신규 입사자가 원인 모를 부작용에 시간을 쏟는다
-
② 디버깅이 어렵다
- 스택 트레이스에 안 나온다
-
③ 쓰기 경로에 부하와 락을 더한다
- 대량 INSERT 시 행마다 실행된다
-
④ 대량 작업에서 폭발한다
- 100만 행 UPDATE → 트리거 100만 번
확인하는 법
-- PostgreSQL: 이 테이블에 어떤 트리거가 걸려 있나
SELECT tgname, pg_get_triggerdef(oid) FROM pg_trigger
WHERE tgrelid = 'member'::regclass AND NOT tgisinternal;
-- MySQL
SHOW TRIGGERS LIKE 'member';
성능 문제를 조사할 때 트리거 목록을 먼저 확인하는 습관이 필요하다.
저장 프로시저는 어떤가
-
장점 — 네트워크 왕복 감소 · DB 안에서 집합 연산
-
단점 — 버전 관리·테스트·배포가 애플리케이션 코드보다 훨씬 불편하다
- 벤더 종속(PL/pgSQL ↔ MySQL 문법이 다르다)
-
요즘은 대량 배치 처리처럼 왕복이 결정적인 곳으로 용도가 좁아졌다
실무 기준
- 트리거로 — 빠지면 안 되는 것 (감사 로그 · updated_at · 정합성 보정)
- 코드로 — 업무 로직 (주문 상태 전이 · 할인 계산)
면접 함정
- ❌ "트리거로 업무 로직을 넣으면 안전하다" → 안전하지만 유지보수가 급격히 나빠진다. 범위를 좁게 유지한다.
- ❌ "트리거는 트랜잭션 밖에서 돈다" → 같은 트랜잭션 안이다. 실패하면 원래 문장까지 롤백된다.
대량 작업에서 무슨 일이 생기나
-- 행마다 도는 트리거가 걸린 테이블에 대량 UPDATE
UPDATE member SET status = 'ACTIVE' WHERE status IS NULL; -- 100만 행
-- → 트리거가 100만 번 실행된다
-- → 각각이 다른 테이블을 갱신하면 락도 100만 번
-- 문장 단위 트리거로 바꾸면 한 번만 돈다 (PostgreSQL)
CREATE TRIGGER trg_stmt AFTER UPDATE ON member
REFERENCING NEW TABLE AS changed
FOR EACH STATEMENT EXECUTE FUNCTION handle_batch();
FOR EACH STATEMENT + 전이 테이블(NEW TABLE)을 쓰면 변경된 행 전체를 한 번에 집합으로 처리할 수 있다. 대량 작업 성능이 완전히 달라진다.
일시적으로 끄기
ALTER TABLE member DISABLE TRIGGER trg_audit; -- 대량 이관 중
-- ... 작업 ...
ALTER TABLE member ENABLE TRIGGER trg_audit; -- 반드시 다시 켠다 (잊으면 감사 구멍)