avgState — avg의 중간 상태를 저장하는 예제
avgState — avg의 중간 상태를 저장하는 예제
avgState는 avg 함수에 State 결합자를 적용해서 평균 계산에 필요한 중간 상태를 AggregateFunction(avg, T) 타입으로 저장하는 예제를 보여드릴게요.
출처: 문서
본문
avg 함수에 State 결합자를 적용하면 T를 지정 타입으로 하는 AggregateFunction(avg, T) 타입의 중간 상태를 만들어 낼 수 있어요.
이번 예제에서는 AggregateFunction 타입을 avgState 함수와 함께 사용해서 웹사이트 트래픽 데이터를 집계하는 방법을 살펴볼게요. 먼저 웹사이트 트래픽 데이터를 위한 원본 테이블을 만들어요:
CREATE TABLE raw_page_views
(
page_id UInt32,
page_name String,
response_time_ms UInt32, -- Page response time in milliseconds
viewed_at DateTime DEFAULT now()
)
ENGINE = MergeTree()
ORDER BY (page_id, viewed_at);
평균 응답 시간을 저장할 집계 테이블을 만들어요. avg는 복잡한 상태(합과 개수)가 필요하므로 SimpleAggregateFunction 타입을 쓸 수 없어요. 그래서 AggregateFunction 타입을 사용해요:
CREATE TABLE page_performance
(
page_id UInt32,
page_name String,
avg_response_time AggregateFunction(avg, UInt32) -- Stores the state needed for avg calculation
)
ENGINE = AggregatingMergeTree()
ORDER BY page_id;
새 데이터에 대한 삽입 트리거 역할을 하면서, 위에서 정의한 대상 테이블에 중간 상태 데이터를 저장할 Incremental materialized view를 만들어요:
CREATE MATERIALIZED VIEW page_performance_mv
TO page_performance
AS SELECT
page_id,
page_name,
avgState(response_time_ms) AS avg_response_time -- Using -State combinator
FROM raw_page_views
GROUP BY page_id, page_name;
원본 테이블에 초기 데이터를 삽입해서 디스크에 part를 만들어요:
INSERT INTO raw_page_views (page_id, page_name, response_time_ms) VALUES
(1, 'Homepage', 120),
(1, 'Homepage', 135),
(2, 'Products', 95),
(2, 'Products', 105),
(3, 'About', 80),
(3, 'About', 90);
데이터를 더 삽입해서 디스크에 두 번째 part를 만들어요:
INSERT INTO raw_page_views (page_id, page_name, response_time_ms) VALUES
(1, 'Homepage', 150),
(2, 'Products', 110),
(3, 'About', 70),
(4, 'Contact', 60),
(4, 'Contact', 65);
대상 테이블 page_performance를 확인해볼게요:
SELECT
page_id,
page_name,
avg_response_time,
toTypeName(avg_response_time)
FROM page_performance
┌─page_id─┬─page_name─┬─avg_response_time─┬─toTypeName(avg_response_time)──┐
│ 1 │ Homepage │ � │ AggregateFunction(avg, UInt32) │
│ 2 │ Products │ � │ AggregateFunction(avg, UInt32) │
│ 3 │ About │ � │ AggregateFunction(avg, UInt32) │
│ 1 │ Homepage │ � │ AggregateFunction(avg, UInt32) │
│ 2 │ Products │ n │ AggregateFunction(avg, UInt32) │
│ 3 │ About │ F │ AggregateFunction(avg, UInt32) │
│ 4 │ Contact │ } │ AggregateFunction(avg, UInt32) │
└─────────┴───────────┴───────────────────┴────────────────────────────────┘
avg_response_time 컬럼이 AggregateFunction(avg, UInt32) 타입이고 중간 상태 정보를 저장한다는 걸 확인할 수 있어요. 또 avg_response_time의 행 데이터는 읽을 수 없고 �, n, F, } 같은 이상한 문자들이 보이는데요, 이는 터미널이 이진 데이터를 텍스트로 표시하려 하기 때문이에요. AggregateFunction 타입은 상태를 효율적인 저장·계산에 최적화된 이진 형식으로 저장하지, 사람이 읽기 좋은 형식으로 저장하지 않아요. 이 이진 상태에는 평균을 계산하는 데 필요한 모든 정보가 담겨 있어요. 이걸 실제로 사용하려면 Merge 결합자를 써요:
SELECT
page_id,
page_name,
avgMerge(avg_response_time) AS average_response_time_ms
FROM page_performance
GROUP BY page_id, page_name
ORDER BY page_id;
이제 올바른 평균 값이 보여요:
┌─page_id─┬─page_name─┬─average_response_time_ms─┐
│ 1 │ Homepage │ 135 │
│ 2 │ Products │ 103.33333333333333 │
│ 3 │ About │ 80 │
│ 4 │ Contact │ 62.5 │
└─────────┴───────────┴──────────────────────────┘