메인 콘텐츠로 건너뛰기
이 문서에서는 lazy materialization의 작동 방식과 이것이 ClickHouse의 전반적인 I/O 최적화 스택에 어떻게 포함되는지 설명합니다. 또한 lazy materialization이 쿼리 성능을 어떻게 향상시키는지 보여 주는 실제 예시를 소개합니다.
버전 25.4부터 사용 가능lazy materialization은 ClickHouse 버전 25.4에서 도입되었으며 기본적으로 활성화되어 있습니다.

개요

수년에 걸쳐 ClickHouse는 I/O를 과감하게 줄이기 위해 여러 계층의 최적화 기법을 도입해 왔습니다. 이러한 기법은 ClickHouse의 속도와 효율성을 뒷받침하는 기반입니다:
최적화설명
컬럼 지향 스토리지쿼리에 필요하지 않은 컬럼 전체를 건너뛸 수 있으며, 유사한 값을 함께 묶어 높은 압축률도 달성할 수 있으므로 데이터 로딩 중 I/O를 최소화합니다.
희소 프라이머리 인덱스보조 데이터 스키핑 인덱스프로젝션_인덱싱된 컬럼_의 필터와 일치할 가능성이 있는 그래뉼 (행 블록)을 식별해 관련 없는 데이터를 프루닝합니다. 이러한 기법은 그래뉼 수준에서 동작하며, 각각 단독으로 또는 조합해 사용할 수 있습니다.
PREWHERE인덱싱되지 않은 컬럼의 필터에 대해서도 일치 여부를 확인해, 그렇지 않으면 로드된 후 버려질 데이터를 미리 건너뜁니다. 이는 독립적으로 동작할 수도 있고, 인덱스가 선택한 그래뉼을 더 정교하게 좁히는 데 사용될 수도 있으며, 모든 컬럼 필터와 일치하지 않는 행을 건너뛰어 그래뉼 프루닝을 보완합니다.
쿼리 조건 캐시이전 실행에서 어떤 그래뉼이 모든 필터와 일치했는지를 기억해 반복 쿼리를 더 빠르게 처리합니다. 따라서 쿼리 구조가 바뀌더라도 ClickHouse는 일치하지 않았던 그래뉼을 읽고 필터링하는 작업을 건너뛸 수 있습니다.
앞서 언급한 I/O 최적화는 읽어야 하는 데이터를 크게 줄일 수 있지만, 여전히 WHERE 절을 통과한 행의 모든 컬럼을 정렬, 집계, LIMIT 같은 작업을 수행하기 전에 로드해야 한다고 가정합니다. 하지만 일부 컬럼은 나중에야 필요하거나, 어떤 데이터는 WHERE 절을 통과하더라도 결국 전혀 필요하지 않다면 어떨까요? 이때 lazy materialization이 필요합니다. 이는 I/O 최적화 스택을 완성하는 별개의 개선 기법입니다:
  • 인덱싱은 PREWHERE와 함께 WHERE 절의 컬럼 필터와 일치하는 행만 처리되도록 보장합니다.
  • Lazy materialization은 이를 바탕으로, 쿼리 실행 계획에서 실제로 필요해질 때까지 컬럼 읽기를 미룹니다. 필터링 이후에도 다음 작업(예: 정렬)에 필요한 컬럼만 즉시 로드됩니다. 나머지 컬럼은 뒤로 미뤄지며, LIMIT 때문에 최종 결과를 만드는 데 필요한 만큼만, 즉 대개 일부만 읽으면 됩니다. 따라서 lazy materialization은 Top N 쿼리에서 특히 강력합니다. 최종 결과를 만들기 위해 특정 컬럼들(대개 크기가 큰 컬럼들)에서 소수의 행만 필요할 수 있기 때문입니다.

예시로 살펴보기

lazy materialization을 자세히 알아보려면 “ClickHouse gets lazier (and faster): Introducing lazy materialization” 블로그 게시물을 참고하시기를 강력히 권장합니다. 아래 예시는 앞서 언급한 블로그 게시물에서 가져온 내용을 여기에서 다시 소개한 것으로, lazy materialization을 통해 ClickHouse 쿼리 실행 시간이 219초에서 단 139밀리초로 단축될 수 있음을 보여줍니다(1576배 향상). 인덱싱과 PREWHERE의 이점을 활용하려면 쿼리에 필터가 있어야 합니다. 인덱싱에는 프라이머리 키(primary key) 컬럼에 대한 필터가 필요하고, PREWHERE에는 임의의 컬럼에 대한 필터가 필요합니다. 그 위에 lazy materialization을 자연스럽게 적용할 수 있지만, 앞서 언급한 다른 최적화와는 달리 컬럼 필터가 전혀 없는 쿼리도 가속할 수 있습니다. 다음 예시 쿼리는 날짜, 제품, 평점, 검증 상태와 관계없이 도움이 되었다는 투표 수가 가장 많은 Amazon 리뷰를 찾고, 제목, 헤드라인, 전체 텍스트와 함께 상위 3개를 반환합니다. 먼저 lazy materialization을 비활성화한 상태에서(query_plan_optimize_lazy_materialization 사용), 쿼리를 콜드 파일 시스템 캐시 상태로 실행합니다:
Query
SELECT
    helpful_votes,
    product_title,
    review_headline,
    review_body
FROM amazon.amazon_reviews
ORDER BY helpful_votes DESC
LIMIT 3
FORMAT Vertical
SETTINGS
    query_plan_optimize_lazy_materialization = false;
Response
Row 1:
──────
helpful_votes:   47524
product_title:   Kindle: Amazon's Original Wireless Reading Device (1st generation)
review_headline: Why and how the Kindle changes everything
review_body:     This is less a \"pros and cons\" review than a hopefully use...

Row 2:
──────
helpful_votes:   41393
product_title:   BIC Cristal For Her Ball Pen, 1.0mm, Black, 16ct (MSLP16-Blk)
review_headline: FINALLY!
review_body:     Someone has answered my gentle prayers and FINALLY designed ...

Row 3:
──────
helpful_votes:   41278
product_title:   The Mountain Kids 100% Cotton Three Wolf Moon T-Shirt
review_headline: Dual Function Design
review_body:     This item has wolves on it which makes it intrinsically swee...

0 rows in set. Elapsed: 219.071 sec. Processed 150.96 million rows, 71.38 GB (689.08 thousand rows/s., 325.81 MB/s.)
Peak memory usage: 1.11 GiB.
다음으로 쿼리를 다시 실행합니다(이번에도 콜드 파일 시스템 캐시로 실행). 이번에는 lazy materialization을 활성화한 상태입니다:
Query
SELECT
    helpful_votes,
    product_title,
    review_headline,
    review_body
FROM amazon.amazon_reviews
ORDER BY helpful_votes DESC
LIMIT 3
FORMAT Vertical
SETTINGS
query_plan_optimize_lazy_materialization = true;
일반적으로는 query_plan_optimize_lazy_materialization = true를 명시적으로 설정하지 않아도 lazy materialization의 이점을 얻을 수 있습니다. 기본적으로 활성화되어 있습니다.
Response
Row 1:
──────
helpful_votes:   47524
product_title:   Kindle: Amazon's Original Wireless Reading Device (1st generation)
review_headline: Why and how the Kindle changes everything
review_body:     This is less a \"pros and cons\" review than a hopefully use...

Row 2:
──────
helpful_votes:   41393
product_title:   BIC Cristal For Her Ball Pen, 1.0mm, Black, 16ct (MSLP16-Blk)
review_headline: FINALLY!
review_body:     Someone has answered my gentle prayers and FINALLY designed ...

Row 3:
──────
helpful_votes:   41278
product_title:   The Mountain Kids 100% Cotton Three Wolf Moon T-Shirt
review_headline: Dual Function Design
review_body:     This item has wolves on it which makes it intrinsically swee...

0 rows in set. Elapsed: 0.139 sec. Processed 150.96 million rows, 1.81 GB (1.09 billion rows/s., 13.06 GB/s.)
Peak memory usage: 3.80 MiB.
lazy materialization을 끈 경우와 켠 경우의 성능 차이를 살펴보겠습니다:
메트릭lazy materialization 비활성화lazy materialization 활성화개선 효과
경과 시간219.071 sec0.139 sec약 1576배 더 빠름
읽은 데이터 양71.38 GB1.81 GB약 40배 감소
최대 메모리 사용량1.11 GiB3.80 MiB약 300배 감소

쿼리 실행 계획에서 lazy materialization을 확인하는 방법

EXPLAIN 절을 사용해 쿼리의 논리 실행 계획을 살펴보면, 앞선 쿼리에서 lazy materialization이 사용되었는지 확인할 수 있습니다:
EXPLAIN actions = 1
SELECT
    helpful_votes,
    product_title,
    review_headline,
    review_body
FROM amazon.amazon_reviews
ORDER BY helpful_votes DESC
LIMIT 3
SETTINGS
    query_plan_optimize_lazy_materialization = true;
...
Lazily read columns: review_headline, review_body, product_title
  Limit
    Sorting
      ReadFromMergeTree
연산자 계획은 아래에서 위로 읽을 수 있으며, ClickHouse가 정렬과 제한을 적용한 후에야 3개의 큰 String 컬럼을 읽는다는 점을 확인할 수 있습니다.
마지막 수정일 2026년 6월 10일