MySQL에서 열(LAG) 지연 처리란?
MySQL에서 열을 지연(LAG) 처리한다는 것은 현재 행의 값과 함께 이전 행의 값을 참조해 계산하는 것을 의미합니다. 오라클이나 SQL Server와 달리 구버전 MySQL에는 LAG() 윈도우 함수가 내장되어 있지 않기 때문에, 사용자 정의 변수를 활용해 직접 구현해야 합니다.
먼저 예제에 사용할 테이블을 생성하겠습니다. 테이블 생성 쿼리는 다음과 같습니다.
mysql> create table LagDemo
-> (
-> UserId int,
-> UserValue int
-> );
Query OK, 0 rows affected (1.74 sec)
예제 데이터 삽입
INSERT 명령을 사용해 테이블에 여러 개의 레코드를 삽입합니다. 쿼리는 다음과 같습니다.
mysql> insert into LagDemo values(12,158); Query OK, 1 row affected (0.61 sec) mysql> insert into LagDemo values(18,756); Query OK, 1 row affected (0.21 sec) mysql> insert into LagDemo values(15,346); Query OK, 1 row affected (0.25 sec) mysql> insert into LagDemo values(87,646); Query OK, 1 row affected (0.14 sec) mysql> insert into LagDemo values(27,334); Query OK, 1 row affected (0.11 sec) mysql> insert into LagDemo values(90,968); Query OK, 1 row affected (0.08 sec) mysql> insert into LagDemo values(84,378); Query OK, 1 row affected (0.10 sec) mysql> insert into LagDemo values(85,546); Query OK, 1 row affected (0.56 sec)
SELECT 문으로 테이블의 모든 레코드를 조회해 보겠습니다.
mysql> select *from LagDemo;
조회 결과
+--------+-----------+ | UserId | UserValue | +--------+-----------+ | 12 | 158 | | 18 | 756 | | 15 | 346 | | 87 | 646 | | 27 | 334 | | 90 | 968 | | 84 | 378 | | 85 | 546 | +--------+-----------+ 8 rows in set (0.00 sec)
LAG 쿼리 작성하기
다음은 MySQL에서 열을 지연(LAG) 처리하는 쿼리입니다. 먼저 두 개의 사용자 정의 변수 @f와 @s를 초기화한 뒤, 서브쿼리에서 각 행에 순번(RowNumber)을 부여합니다. 이후 자기 조인(Self Join)으로 현재 행과 이전 행을 연결하고, 두 값의 나눗셈 결과를 LAG 컬럼으로 출력합니다.
mysql> SET @f := 0; Query OK, 0 rows affected (0.00 sec) mysql> SET @s := 2; Query OK, 0 rows affected (0.00 sec) mysql> SELECT l1.UserId, l1.UserValue , l1.UserValue / l2.UserValue AS 'LAG' -> FROM -> (SELECT if(@f, @f := @f+1, @f:=1) as RowNumber, UserId, UserValue FROM LagDemo) AS l1 -> LEFT JOIN -> (SELECT if(@s, @s := @s+1, @s := 1) as RowNumber, UserId, UserValue FROM LagDemo) AS l2 -> ON l1.RowNumber = l2.RowNumber;
실행 결과
+--------+-----------+--------+ | UserId | UserValue | LAG | +--------+-----------+--------+ | 12 | 158 | NULL | | 18 | 756 | NULL | | 15 | 346 | 2.1899 | | 87 | 646 | 0.8545 | | 27 | 334 | 0.9653 | | 90 | 968 | 1.4985 | | 84 | 378 | 1.1317 | | 85 | 546 | 0.5640 | +--------+-----------+--------+ 8 rows in set (0.00 sec)
결과 해석
이 예제에서는 @s를 2로 초기화했기 때문에, 각 행의 LAG 값은 두 행 위에 있는 값으로 현재 값을 나눈 비율입니다. 예를 들어 세 번째 행(346)은 첫 번째 행(158)과 비교되어 2.1899가 됩니다. 첫 번째와 두 번째 행은 비교할 이전 값이 없으므로 NULL로 표시됩니다. 만약 바로 이전 행과 비교하고 싶다면 @s를 1로 설정하면 됩니다.
참고: MySQL 8.0 이상에서는 LAG() 함수 사용 권장
MySQL 8.0부터는 LAG() 윈도우 함수가 공식적으로 지원되므로, 복잡한 변수 조작 없이 아래처럼 훨씬 간단하게 작성할 수 있습니다.
SELECT UserId,
UserValue,
UserValue / LAG(UserValue, 1) OVER (ORDER BY UserId) AS LAG
FROM LagDemo;
윈도우 함수 방식이 코드도 직관적이고 성능 면에서도 유리하므로, 환경이 허용된다면 최신 문법을 사용하는 것이 좋습니다.