TreasureData에서 효과적인 중간 테이블 활용 예
4103 단어 TreasureData
time
컬럼을 이용해 SQL로 취득하는 데이터 기간을 지정하는 것으로, 불필요한 데이터 I/O를 막아, 효율적으로 처리를 실시할 수가 있습니다.그러나, 전 기간의 데이터를 읽는 집계를 많이 실시하는 경우, 데이터의 I/O에 많은 시간이 걸려 버리는 등에 의해, 자원을 유효하게 활용할 수 없다고 하는 위험성이 있습니다. 따라서 모든 데이터 읽기가 필요한 집계의 공통 처리 결과를 사전에 중간 테이블로 다른 테이블에 저장해두면 리소스를 효과적으로 활용할 수 있게 됩니다.
중간 테이블의 사용 예
예를 들어 모든 사용자마다 사이트에 대한 첫 번째 액세스 시간과 마지막 액세스 시간을 찾는 경우가 있습니다.
서비스 수가 늘어남에 따라 2012년에 마지막으로 방문한 사용자와 2017년에 마지막으로 방문한 사용자 등 다양한 사용자가 나옵니다. 단순히 위의 요구 사항을 요구하기 위해 쿼리를 작성하면 2012년부터 2017년의 데이터에 대해 처음과 마지막 액세스 시간을 요구하는 쿼리를 작성하게 됩니다. 달에 수십억 PV 있는 사이트의 액세스 로그에 대해, 이러한 쿼리를 수십 종류나 hourly로 던져져 버린 날에는 아무리 자원이 있어도 괴로운 기분이 되네요.
중간 테이블을 만들 때까지의 흐름
1. 첫 번째 집계 쿼리를 실행하는 명령
first_access_time: user_id가 처음 액세스한 시간
last_access_time: user_id가 마지막으로 액세스한 시간
sample_db: 작업용 DB
access: 원래 테이블
snapshot_access: 중간 테이블
TD의 Hive 쿼리를 예로 든다. 아래에서는 2017년 3월 1일 시점에서 snapshot을 작성하고 있으며, 그 날의 모든 유저의 최초로 액세스한 날과 마지막으로 액세스한 날이 저장되어 있습니다.
INSERT INTO TABLE snapshot_access
SELECT * FROM (
SELECT
TD_TIME_PARSE('2017-03-01','JST') AS time,
user_id,
TD_FIRST(time, time) AS first_access_time,
TD_LAST(time, time) AS last_access_time
FROM access
WHERE TD_TIME_RANGE(time, null, '2017-03-01', 'JST')
GROUP BY user̲id
) all
2. 중간 테이블 작성을 위해 매일 1시에 실행되는 스케줄 쿼리
스케줄 쿼리로 다음을 등록합니다. (지금이라면 TD Workflow(digdag) 등을 사용해도 좋네요.)
서브쿼리의 첫째는 access 테이블의 전일분 액세스가 있던 유저의 최초의 액세스일과 마지막 성공일의 집계를 실시합니다.
또 다른 하위 쿼리가 포인트로 작성된 snapshot_access에서 며칠 분 모은 첫 번째 액세스 날짜와 마지막 액세스 날짜의 로그를 추출하고 위와 UNION ALL하여 다시 모든 사용자의 첫 번째 및 마지막 액세스 날짜를 요청합니다.
이것을 하면 snapshot_access의 1일분은 반드시 전체 유저 ID분의 로그 밖에 쌓이지 않기 때문에, 매번 전 기간을 집계하지 않아도 최초와 마지막 액세스일을 추출할 수 있게 됩니다.
-- aggregate data from (aggregated historical aggregated data) + (aggregated todays data)
INSERT INTO TABLE snapshot_access
SELECT
TD_SCHEDULED_TIME() AS time,
user̲id,
TD_FIRST(first_access_time, first_access_time) AS first_access_time,
TD_LAST(last_access_time, last_access_time) AS last_access_time
FROM (
-- aggregates todays data
SELECT
user_id,
TD_FIRST(time, time) AS first_access_time,
TD_LAST(time, time) AS last_access_time
FROM access
WHERE TD_TIME_RANGE(time, TD_TIME_ADD(TD_SCHEDULED_TIME(), '-1d', 'JST'), TD_SCHEDULED_TIME(), 'JST')
GROUP BY user_id
UNION ALL
-- aggregate historically aggregated data
SELECT
user_id,
TD_FIRST(first_access_time, time) AS first_access_time,
TD_LAST(last_access_time, time) AS last_access_time
FROM snapshot_access
WHERE TD_TIME_RANGE(time, TD_TIME_ADD(TD_SCHEDULED_TIME(), '-5d', 'JST'), TD_SCHEDULED_TIME(), 'JST')
GROUP BY user_id
) historical_data_plus_todays_data
GROUP BY user_id
3. 집계 쿼리 예
마지막으로 snapshot_access를 사용하는 경우 아래와 같은 쿼리를 작성합니다.
매일 신규 고유 사용자 수를 계산하는 예 :
SELECT
first_access_time AS day,
COUNT(1) AS uu
FROM
(
SELECT
user_id,
TD_TIME_FORMAT( TD_FIRST(first_access_time, first_access_time), 'yyyy‒MM‒dd', 'JST') AS
first_access_day
FROM snapshot_access
WHERE TD_TIME_RANGE(time, TD_TIME_ADD(TD_SCHEDULED_TIME(), '-1d', 'JST'), NULL, 'JST')
GROUP BY user_id
) first_access_table
WHERE
first_access_time = TD_TIME_FORMAT(TD_SCHEDULED_TIME(), 'yyyy‒MM‒dd', 'JST')
GROUP BY first_access_time
요약
중간 테이블을 사용하면 효율적으로 처리할 수 있게 된다. 라는 이야기였습니다.
한편으로 역기로 해결하는 방법도 있습니다만, 워크플로우 시스템이 편리하게 사용할 수 있게 되어 있기 때문에, 효율적인 처리 플로우로 할 수 있는 곳은 그러한 것이 좋네요.
Reference
이 문제에 관하여(TreasureData에서 효과적인 중간 테이블 활용 예), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/toru-takahashi/items/5597ce057ce35fbd05dd텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)