avgState — avg의 중간 상태를 저장하는 예제

avgState — avg의 중간 상태를 저장하는 예제

avgStateavg 함수에 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 │
└─────────┴───────────┴──────────────────────────┘

더 알아보기 (Learn more)