MySQL에서 FOR EACH ROW는 말 그대로 UPDATE 또는 DELETE 문에 의해 영향을 받는(매칭되는) 각 행(row)마다 트리거 본문이 실행된다는 의미입니다. 즉, 트리거가 테이블 전체에 딱 한 번 적용되는 것이 아니라, 조건에 해당하는 행의 수만큼 트리거 본문이 반복해서 실행됩니다.
이 개념은 실제 예제를 통해 훨씬 명확하게 이해할 수 있습니다. 아래에서 삭제되는 각 행마다 트리거가 어떻게 동작하는지 단계별로 살펴보겠습니다.
예제를 위한 테이블 준비
먼저 예제에 사용할 두 개의 테이블, 즉 원본 데이터를 담을 Sample 테이블과 영향받은 행 수를 기록할 Sample_rowaffected 테이블을 생성합니다.
mysql> Create table Sample(id int, value varchar(20)); Query OK, 0 rows affected (0.47 sec) mysql> Insert into Sample(id, value) values(100, 'same'),(101, 'Different'),(500, 'excellent'),(501, 'temporary'); Query OK, 4 rows affected (0.04 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> Select * from Sample; +------+-----------+ | id | value | +------+-----------+ | 100 | same | | 101 | Different | | 500 | excellent | | 501 | temporary | +------+-----------+ 4 rows in set (0.00 sec) mysql> Create table Sample_rowaffected(id int); Query OK, 0 rows affected (0.53 sec) mysql> Select Count(*) as 'Rows Affected' from sample_rowaffected; +---------------+ | Rows Affected | +---------------+ | 0 | +---------------+ 1 row in set (0.10 sec)
Sample 테이블에는 총 4개의 행이 들어 있고, 아직 Sample_rowaffected 테이블은 비어 있는 상태(영향받은 행 수 0건)입니다.
BEFORE DELETE 트리거 생성
이제 Sample 테이블에서 행이 삭제되기 직전에 실행되는 트리거를 만들어 보겠습니다. 이 트리거는 사용자 변수 @count를 1씩 증가시키고, 그 값을 sample_rowaffected 테이블에 기록합니다.
mysql> Delimiter //
mysql> Create trigger trigger_before_delete_sample BEFORE DELETE on
Sample
-> FOR EACH ROW
-> BEGIN
-> SET @count = if (@count IS NULL, 1, (@count+1));
-> INSERT INTO sample_rowaffected values (@count);
-> END ;
-> //
Query OK, 0 rows affected (0.15 sec)
mysql> Delimiter ;여기서 주목할 부분은 바로 FOR EACH ROW 구문입니다. 이 구문 덕분에 DELETE 문으로 여러 행이 한꺼번에 삭제되더라도, 삭제되는 각 행마다 BEGIN~END 사이의 트리거 본문이 개별적으로 실행됩니다.
행 삭제 후 결과 확인
다음 쿼리는 Sample 테이블에서 ID가 500 이상인 행들을 삭제하며, 삭제된 행의 개수가 사용자 변수 @count에 저장됩니다.
mysql> Delete from Sample WHERE ID >=500; Query OK, 2 rows affected (0.11 sec) mysql> Select @count; +--------+ | @count | +--------+ | 2 | +--------+ 1 row in set (0.03 sec)
DELETE 문으로 2개의 행이 삭제되었고, @count 값도 2로 기록되었습니다. 이어서 sample_rowaffected 테이블을 조회해 실제로 트리거가 몇 번 실행되었는지 확인해 보겠습니다.
mysql> Select Count(*) as 'Rows Affected' from sample_rowaffected; +---------------+ | Rows Affected | +---------------+ | 2 | +---------------+ 1 row in set (0.00 sec) mysql> Select * from Sample; +------+-----------+ | id | value | +------+-----------+ | 100 | same | | 101 | Different | +------+-----------+ 2 rows in set (0.00 sec)
결론
위 예제의 결과를 보면 분명해집니다. DELETE 문 하나로 2개의 행이 삭제되었지만, 트리거 본문은 총 2번 실행되어 sample_rowaffected 테이블에 2개의 레코드가 기록되었습니다.
이것이 바로 FOR EACH ROW의 핵심입니다. 트리거는 문(statement) 단위가 아니라 UPDATE 또는 DELETE 등의 DML 문에 의해 매칭되어 변경되는 각 행마다 트리거 본문을 실행합니다. 따라서 영향받는 행이 많을수록 트리거도 그만큼 여러 번 실행된다는 점을 반드시 기억해야 하며, 대량의 데이터를 처리하는 쿼리에서 트리거를 사용할 때는 성능에 미치는 영향도 함께 고려하는 것이 좋습니다.