이동준1
아웃풋 공부
이동준1
전체 방문자
오늘
어제
  • 분류 전체보기 (87)
    • airflow (8)
    • sql (23)
    • aws (12)
    • python (3)
    • 네트워크 (12)
    • 알고리즘 (2)
    • 짧은서평 (27)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 유연함의힘
  • Network
  • 통증해방 서평
  • 마음의기술 서평
  • 통증해방
  • 고통의비밀
  • regexp
  • 퓨처셀프
  • 서평
  • 네트워크
  • AWS
  • 마음의기술
  • 고통의 비밀

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
이동준1

아웃풋 공부

sql

[sql] DAU2

2024. 3. 16. 20:13

이전 포스팅에서는 DAU를 정적으로 구하는 방법을 알아보았고, 이번에는 DAU를 동적으로 구하는 방법을 알아본다. DAU를 동적으로 계산하는 방법은 아래 2가지가 있었는데, 이번 포스팅에서는반복문과 변수를 활용하는 방법에 대해서 쓰겠다

① 반복문과 변수를 활용해서 insert into
② cross join

 

목적은 90일치 각각의 DAU, WAU, MAU 를 계산해서 테이블화 하는 것이다. 각 지표들은 각 기준날짜로부터 계산된 DAU, WAU, MAU 이어야한다. 각 일자마다 세 지표가 다르게 계산되어야 하는 것이다. 이는 아래 4단계를 거쳐 완성해보도록 한다.

 

① 테이블 생성

② 변수선언

③ for loop 생성

④ transaction 처리

 

① 먼저 일자와 각 지표들을 담을 테이블은 만들어준다. 테이블은 만든뒤, insert into를 반복실행해서 90일치의 지표들을 기입해줄 것이다.

create table if not exists daily_acquistions
(d_day date,
dau integer,
wau integer,
mau integer
);

 

② 다음으로는 변수를 선언해준다. 기존 session 테이블의 최신일자가 '2016-10-31' 이므로, 최신일자부터 시작해서 지표를 계산하기위해 current_date_input 변수에 해당일자를 담아준다. 그리고 정수형 타입의 i 변수를 선언해주었는데, 이는 날짜를 하나씩 차감하면서 계산하는 용도로 사용할 것이다.

DECLARE
    current_date_input DATE := '2016-10-31';
    i INT;

 

③ 변수를 지정해줬으면, 지정한 변수를 이용해서 for loop를 만들어준다. FOR i IN 0..89 LOOP 라는 문법으로 루프를 형성해주면 i 라는 변수는 0부터 89까지 반복되면서 루프내의 쿼리를 실행한다. 

FOR i IN 0..89 LOOP
	..
END LOOP;

 

우리는 '2016-10-31' 일자부터 시작해서 과거 90일의 DAU, WAU, MAU를 구해야한다. 이는 loop내에서 위에서 선언한 current_date_input 변수에서 날짜를 0부터 89까지 차감하면서 각 지표를 구해준다. '2016-10-31'의 (DAU, WAU, MAU)를 구한뒤, '2016-10-30'의 (DAU, WAU, MAU)를 구하고, '2016-10-31' - '89일'의 (DAU, WAU, MAU) 까지 구해주는 것이다. 반영한 쿼리는 아래와 같다.

FOR i IN 0..89 LOOP
	INSERT INTO daily_acquisitions (d_day, dau, wau, mau)
	SELECT
	    current_date_input - i AS d_day,
	    (SELECT COUNT(DISTINCT user_id)
	     FROM ga_sess
	     WHERE visit_stime >= (current_date_input - i - INTERVAL '1 days')
	       AND visit_stime < (current_date_input - i)) AS dau,
	    (SELECT COUNT(DISTINCT user_id)
	     FROM ga_sess
	     WHERE visit_stime >= (current_date_input - i - INTERVAL '7 days')
	       AND visit_stime < (current_date_input - i)) AS wau,
	    (SELECT COUNT(DISTINCT user_id)
	     FROM ga_sess
	     WHERE visit_stime >= (current_date_input - i - INTERVAL '30 days')
	       AND visit_stime < (current_date_input - i)) AS mau;
END LOOP;

 

④ 마지막으로 DO $$ .. END $$; 로 쿼리를 감싸주어, 쿼리가 트랜잭션으로 처리되도록 해준다. 데이터 정합성을 위해서 반복문내의 쿼리를 한덩이로 묶어서 도중에 실패한다면 쿼리문 전체가 실패하도록 처리한다. 

DO $$
DECLARE
    current_date_input DATE := '2016-10-31';
    i INT;
BEGIN
    FOR i IN 0..89 LOOP
        INSERT INTO daily_acquisitions (d_day, dau, wau, mau)
        SELECT
            current_date_input - i AS d_day,
            (SELECT COUNT(DISTINCT user_id)
             FROM ga_sess
             WHERE visit_stime >= (current_date_input - i - INTERVAL '1 days')
               AND visit_stime < (current_date_input - i)) AS dau,
            (SELECT COUNT(DISTINCT user_id)
             FROM ga_sess
             WHERE visit_stime >= (current_date_input - i - INTERVAL '7 days')
               AND visit_stime < (current_date_input - i)) AS wau,
            (SELECT COUNT(DISTINCT user_id)
             FROM ga_sess
             WHERE visit_stime >= (current_date_input - i - INTERVAL '30 days')
               AND visit_stime < (current_date_input - i)) AS mau;
    END LOOP;
END $$;

 

그러나 이 쿼리는 시간이 오래걸린다는 단점이 있다. 테이블에 하루치의 데이터를 넣기위해서는 3번의 조회가 필요하며, 이를 90번동안 반복해야 하기때문이다. 3 X 90 = 270, 총 270번의 쿼리를 날려야 90일간의 DAU, WAU, MAU를 구할수 있다. 

 

이 문제를 해결하기 위해서 다음 포스팅에서는 cross join을 이용해서 좀더 효율적으로 지표를 도출하는 방법에 대해 알아본다. 

'sql' 카테고리의 다른 글

[sql] DAU3  (1) 2024.03.19
[sql] recursive CTE2  (0) 2024.03.16
[sql] DAU1  (0) 2024.03.14
[sql] recursive CTE  (0) 2024.02.17
[sql] cross selling  (0) 2024.01.18
    'sql' 카테고리의 다른 글
    • [sql] DAU3
    • [sql] recursive CTE2
    • [sql] DAU1
    • [sql] recursive CTE
    이동준1
    이동준1

    티스토리툴바