Trigger

특정 테이블에 INSERT, DELETE, UPDATE와 같은 DML 문이 수행되었을 때, 데이터베이스에서 자동으로 동작하도록 작성된 프로그램.

예시. 당일 판매 수량 수집하기

아래와 같은 주문 테이블이 있다고 가정해보겠습니다.

필드명 (ORDERS)타입설명
IDINTPK
ORDER_DATEDATETIME주문 시각
QTYINT주문 수량
PRICEINT주문 가격
PRODUCTVARCHAR상품명

이 때, 당일 판매 수량을 체크하고자 다음과 테이블을 구축했습니다.

필드명 (DAILY_ORDERS)타입설명
IDINTPK
SALE_DATEDATETIME수집일
PRODUCTVARCHAR상품명
TOTAL_QTYINT판매 수량
TOTAL_PRICEINT판매 금액
CREATE TABLE ORDERS(  
    ID         INT AUTO_INCREMENT,  
    ORDER_DATE DATETIME NOT NULL,  
    PRODUCT    CHAR(255) NOT NULL,  
    QTY        INT NOT NULL,  
    PRICE      INT NOT NULL,  
  
    PRIMARY KEY (ID)  
);  
  
CREATE TABLE DAILY_ORDERS (  
    ID        INT AUTO_INCREMENT,  
    SALE_DATE DATETIME NOT NULL,  
    PRODUCT   CHAR(255) NOT NULL,  
    TOTAL_QTY INT NOT NULL,  
    TOTAL_PRICE INT NOT NULL,  
  
    PRIMARY KEY (ID)  
);

주문이 들어오는 경우, 해당 주문의 통계를 구하기 위해 DAILY_ORDERS 에 값이 업데이트가 되어야 합니다. 이를 해결하는 방법은 많아보이지만, 우선 TRIGGER 를 이용해 작성해보도록 하겠습니다.

TRIGGER SYNTAX

DELIMITER $$ 
	CREATE TRIGGER {trigger_name} 
	{BEFORE | AFTER} {INSERT | UPDATE| DELETE } 
	ON {table_name} FOR EACH ROW 
	BEGIN 
		-- 트리거 내용 
	END 
DELIMITER ;

TRIGGER 작성하기

위의 문법을 바탕으로, TRIGGER 를 작성해보도록 하겠습니다. 요구사항은 다음과 같습니다.

  • 주문이 들어오는 경우 (ORDERS 테이블에 INSERT되는 경우)
  • DAILY_ORDERS 값 업데이트 하기

요구사항에 해당하는 TRIGGER 는 다음과 같습니다. 여기서 NEW 라는 키워드는 적용될 행을 의미하게 됩니다.

DELIMITER $$  
    CREATE TRIGGER DAILY_ORDER_SUMMARY  
    AFTER INSERT ON ORDERS FOR EACH ROW  
    BEGIN        # 날짜를 저장할 변수를 선언한다.  
        DECLARE ORDERED_DATE DATETIME;  
  
        # 날짜-시간을 날짜로 변환한다.  
        SET ORDERED_DATE = DATE(NEW.ORDER_DATE);  
  
        # 해당 하는 날짜가 없는 경우 날짜에 해당하는 데이터를 미리 삽입한다.  
        IF NOT EXISTS(SELECT * FROM DAILY_ORDERS WHERE SALE_DATE = DATE(NEW.ORDER_DATE) AND PRODUCT = NEW.PRODUCT) THEN  
            INSERT INTO DAILY_ORDERS  
                    (ID, SALE_DATE, PRODUCT, TOTAL_QTY, TOTAL_PRICE)  
                VALUES  
                    (NULL, ORDERED_DATE, NEW.PRODCUT, 0, 0);  
        END IF;  
  
        # 해당 날짜에 해당하는 데이터를 업데이트한다.  
        UPDATE DAILY_ORDERS  
            SET  
                TOTAL_QTY = TOTAL_QTY + NEW.QTY,  
                TOTAL_PRICE = TOTAL_PRICE + NEW.PRICE  
            WHERE  
                SALE_DATE = ORDERED_DATE AND PRODUCT = NEW.PRODUCT;  
    END $$  
DELIMITER ;

실제로 데이터를 넣어보고 그 결과를 살펴보겠습니다

INSERT INTO ORDERS VALUES (NULL, NOW(), 'A', 1, 100);
 
SELECT * FROM ORDERS;
# 1 | 2023-12-28 03:40:02 | A | 1 | 100
 
SELECT * FROM DAILY_ORDERS;
# 1 | 2023-12-28 00:00:00 | A | 1 | 100
 
INSERT INTO ORDERS VALUES (NULL, NOW(), 'B', 1, 50);  
INSERT INTO ORDERS VALUES (NULL, NOW(), 'C', 1, 70);  
INSERT INTO ORDERS VALUES (NULL, NOW(), 'D', 1, 40);  
INSERT INTO ORDERS VALUES (NULL, NOW(), 'E', 1, 100);
 
SELECT * FROM DAILY_ORDERS;
# 1|2023-12-28 00:00:00|A|1|100
# 2|2023-12-28 00:00:00|B|1|50
# 3|2023-12-28 00:00:00|C|1|70
# 4|2023-12-28 00:00:00|D|1|40
# 5|2023-12-28 00:00:00|E|1|100
 

TRIGGER 조회

SHOW TRIGGERS;

TRIGGER 삭제

DROP TRIGGER {trigger_name};

특징

  • 제약 조건 관리 : 새로운 데이터가 삽입되는 경우에 다른 테이블에 해당 데이터를 삽입
  • 데이터 갱신 관리 : 데이터가 갱신되면 다른 테이블의 데이터도 함께 갱신하도록
  • 로그 기록 : 데이터 변경 작업에 대한 로그를 기록
  • 복제 관리 : DB 복제 환경에서 Trigger 를 활용해서 일관성을 유지할 수 있다.

장점

  • Trigger 는 DB의 이벤트(INSERT, UPDATE 등)에 대해서 앞뒤로 실행될 수 있다.
  • TriggerDB 에서 동작하기 때문에 불필요한 Round Trip 시간을 줄일 수 있다.
  • TriggerDB 에서 동작하기 때문에 성능적인 이점을 가져갈 수 있다.

단점

  • 가시성이 좋지 않기 때문에 유지보수에 좋지 않은 영향을 끼칠 수 있다.
  • Transaction Isolation Level 에 따라 동시성 문제가 발생할 수 있다.