Skip to main content
모든 빠른 시작
실시간 분석데이터 웨어하우징관측성AI/MLCloudOss

사전 요구사항

To successfully follow this guide, you’ll need the following: 이 가이드는 uk_price_paid 테이블과 앞서 소개한 개념을 바탕으로 진행되므로, 다음 빠른 시작도 완료되어 있어야 합니다:

만들게 될 내용

MergeTree 퀵스타트에서는 테이블이 (postcode, addr1, addr2) 기준으로 정렬되어 있으므로 town 또는 countyuk_price_paid를 쿼리하려면 전체 테이블 스캔이 필요하다는 점을 살펴보았습니다. 이 퀵스타트에서는 프로젝션을 만들어 이 문제를 해결합니다. 프로젝션은 같은 테이블 내부에 저장되는 추가 정렬 데이터 표현입니다. materialized view와 달리 프로젝션은 별도의 대상 테이블이 필요 없고, 뮤테이션(삭제 및 업데이트)과 동기화된 상태를 유지하며, 쿼리 최적화기가 이를 투명하게 활용하므로 계속 같은 테이블 이름으로 쿼리하면 됩니다. 이 과정을 마치면 프로젝션을 추가하고 구체화하는 방법, ClickHouse가 이를 자동으로 선택하는 방식, 그리고 materialized view보다 프로젝션이 더 적합한 경우를 이해하게 됩니다.
1

프로젝션이 필요한 이유 이해하기

uk_price_paid 테이블은 (postcode, addr1, addr2) 기준으로 정렬되어 있습니다. 즉, postcode, addr1, addr2로 필터링할 때 ClickHouse는 큰 데이터 블록을 건너뛸 수 있지만, town으로 필터링하는 쿼리는 3천만 행 전체를 모두 스캔해야 합니다.프로젝션같은 테이블 내부에 (일부 또는 전체) 컬럼의 추가 정렬 복사본을 저장합니다. 테이블을 쿼리할 때 쿼리 최적화기는 프로젝션을 읽는 편이 기본 데이터보다 더 적은 그래뉼에 접근하는지 자동으로 확인하고, 그렇다면 이를 투명하게 사용합니다.materialized view와의 주요 차이점:
  • 별도의 테이블이 없습니다 - 프로젝션은 uk_price_paid 자체 내부에 존재합니다
  • 투명한 쿼리 최적화 - 평소처럼 uk_price_paid를 쿼리하면 ClickHouse가 자동으로 프로젝션을 선택합니다
  • 뮤테이션과 동기화 상태를 유지합니다 - 테이블에 적용된 삭제 및 업데이트가 프로젝션에도 반영됩니다
자세한 내용은 프로젝션 참고 문서를 참조하십시오.
2

테이블에 프로젝션 추가하기

uk_price_paidtown, date, price, type(town, date) 기준으로 정렬된 상태로 저장하는 프로젝션을 정의합니다:
ALTER TABLE uk_price_paid
    ADD PROJECTION uk_price_paid_by_town
    (
        SELECT town, date, price, type
        ORDER BY (town, date)
    );
이렇게 하면 프로젝션이 테이블의 메타데이터에 등록되지만, 기존 데이터에는 구체화되지 않습니다. 향후 삽입되는 데이터에만 적용됩니다.프로젝션이 테이블 정의에 표시되는지 확인하십시오:
SHOW CREATE TABLE uk_price_paid;
출력 결과에서 PROJECTION uk_price_paid_by_town 블록을 확인할 수 있어야 합니다.
3

기존 데이터에 대해 프로젝션 구체화하기

materialized view와 마찬가지로, 새로 추가한 프로젝션은 이후 삽입되는 데이터에만 적용됩니다. 테이블에 이미 있는 3천만 행으로 이를 채우려면 명시적으로 구체화하십시오:
ALTER TABLE uk_price_paid
    MATERIALIZE PROJECTION uk_price_paid_by_town;
이 작업은 백그라운드 mutation으로 실행됩니다. 진행 상황은 다음과 같이 확인할 수 있습니다:
SELECT
    mutation_id,
    command,
    is_done
FROM system.mutations
WHERE table = 'uk_price_paid'
ORDER BY create_time DESC
LIMIT 5;
is_done = 1이 되면 프로젝션이 완전히 구체화됩니다. system.projection_parts를 확인해서도 검증할 수 있습니다:
SELECT
    name,
    count() AS parts,
    sum(rows) AS total_rows,
    formatReadableSize(sum(bytes_on_disk)) AS size
FROM system.projection_parts
WHERE table = 'uk_price_paid'
  AND active = true
GROUP BY name;
4

테이블(table)을 쿼리하고 projection이 자동으로 사용되는지 확인하기

이제 town으로 필터링하는 쿼리를 실행하세요. 지금까지 계속 쿼리해 온 같은 테이블에서 실행합니다:
SELECT
    toYear(date) AS year,
    round(avg(price)) AS avg_price,
    count() AS sales
FROM uk_price_paid
WHERE town = 'LONDON'
GROUP BY year
ORDER BY year DESC;
쿼리 통계를 확인해 보세요. 프로젝션이 생기기 전보다 읽는 행 수가 훨씬 적습니다. ClickHouse가 기본 데이터를 스캔하는 대신 uk_price_paid_by_town 프로젝션에서 읽도록 자동으로 선택했기 때문입니다.EXPLAIN을 사용하면 프로젝션이 사용되었는지 확인할 수 있습니다:
EXPLAIN
SELECT
    toYear(date) AS year,
    round(avg(price)) AS avg_price,
    count() AS sales
FROM uk_price_paid
WHERE town = 'LONDON'
GROUP BY year
ORDER BY year DESC;
출력에서 프로젝션 이름을 참조하는 ReadFromMergeTree를 확인하십시오. 성능을 명확히 비교하려면 단일 쿼리에서 프로젝션 최적화를 비활성화할 수 있습니다:
SELECT
    toYear(date) AS year,
    round(avg(price)) AS avg_price,
    count() AS sales
FROM uk_price_paid
WHERE town = 'LONDON'
GROUP BY year
ORDER BY year DESC
SETTINGS optimize_use_projections = 0;
이렇게 하면 테이블 전체를 스캔하게 되므로 읽은 행 수의 차이를 확인할 수 있습니다.
5

프로젝션과 materialized view 비교

프로젝션과 materialized view는 모두 같은 문제, 즉 서로 다른 액세스 패턴에서 더 빠른 읽기를 제공하는 문제를 해결하지만, 각기 다른 트레이드오프가 있습니다. 요약하면, 동일한 데이터에 대해 다른 정렬 순서만 필요할 때는 프로젝션이 가장 적합합니다. 반면 데이터를 변환하거나 집계하거나 다른 스키마(schema)로 보내야 할 때는 materialized view가 더 유연합니다. 자세한 비교는 Materialized views versus projections를 참조하십시오.
6

스토리지 오버헤드 확인

프로젝션은 동일한 테이블 내에 선택한 컬럼의 사본을 한 벌 더 저장하므로 디스크 사용량이 증가합니다. system.parts를 쿼리하여 uk_price_paid의 전체 크기(이제 프로젝션 데이터가 포함됨)를 확인하세요:
SELECT
    table,
    count() AS parts,
    sum(rows) AS total_rows,
    formatReadableSize(sum(bytes_on_disk)) AS compressed_size
FROM system.parts
WHERE table = 'uk_price_paid'
  AND active = true
GROUP BY table;
프로젝션별 스토리지도 확인할 수 있습니다.
SELECT
    name,
    count() AS parts,
    sum(rows) AS total_rows,
    formatReadableSize(sum(bytes_on_disk)) AS projection_size
FROM system.projection_parts
WHERE table = 'uk_price_paid'
  AND active = true
GROUP BY name;
이는 구체화된 뷰(Materialized View)와 같은 근본적인 절충입니다. 즉, 더 빠른 읽기를 위해 더 많은 디스크 공간을 사용합니다. 프로젝션은 선택한 4개의 컬럼만 포함하고 정렬 순서에 따라 압축률이 달라지므로 전체 복사본보다 작을 수 있습니다.

다음 단계

이 빠른 시작에서는 uk_price_paid(town, date) 기준으로 정렬된 데이터를 저장하는 프로젝션을 추가해, 별도의 테이블을 만들지 않고도 town 기준으로 빠르게 조회할 수 있도록 했습니다. 또한 프로젝션은 쿼리 최적화기가 자동으로 선택하고, 뮤테이션과 동기화된 상태를 유지하며, 디스크 공간을 사용하는 대신 읽기 성능을 높인다는 점을 배웠습니다. 다음으로 아래 빠른 시작도 확인해 보십시오. 또는 참고 문서에서 더 자세히 알아보십시오.
ClickHouse Academy — Master ClickHouse with expert-designed training for every skill level
Last modified on June 10, 2026