Skip to main content
This article describes how lazy materialization works and how it fits into ClickHouse’s broader I/O optimization stack. It presents a real-world example demonstrating how lazy materialization increases query performance.
Available from version 25.4Lazy materialization was introduced in version 25.4 of ClickHouse, and is turned on by default.

Overview

Over the years, ClickHouse has introduced a series of layered optimizations to aggressively reduce I/O. These techniques form the foundation of its speed and efficiency: While the aforementioned I/O optimizations can significantly reduce data read, they still assume that all columns for rows passing the WHERE clause must be loaded before running operations like sorting, aggregation, or LIMIT. But what if some columns aren’t needed until later, or some data, despite passing the WHERE clause, is never needed at all? That’s where lazy materialization comes in. It is an orthogonal enhancement that completes the I/O optimization stack:
  • Indexing, together with PREWHERE, ensures that only rows matching column filters in the WHERE clause are processed.
  • Lazy materialization builds on this by deferring column reads until they’re actually required by the query execution plan. Even after filtering, only the columns needed for the next operation - such as sorting - are loaded immediately. Others are postponed and, due to LIMIT, are often read only partially, just enough to produce the final result. This makes lazy materialization especially powerful for Top N queries, where the final result may only require a handful of rows from certain, often large, columns.

A worked example

We highly recommend the blogpost “ClickHouse gets lazier (and faster): Introducing lazy materialization” for a deep dive on lazy materialization. The example below is taken from the aforementioned blogpost and reproduced here to demonstrate how a ClickHouse query can go from 219 seconds to just 139 milliseconds (a 1576× speedup) with lazy materialization. To benefit from indexing and PREWHERE, a query needs filters, on primary key columns for indexing, and on any columns for PREWHERE. Lazy materialization layers cleanly on top, but unlike the other optimizations mentioned previously, it can also speed up queries with no column filters at all. Consider the following example query which finds Amazon reviews with the highest number of helpful votes, regardless of date, product, rating, or verification status, and returns the top 3 along with their title, headline, and full text. First running the query (with cold filesystem caches) with lazy materialization disabled (using query_plan_optimize_lazy_materialization):
Query
Response
Next the query is rerun (again with a cold filesystem cache), but this time with lazy materialization enabled:
Query
Ordinarily you don’t need to explicitly set query_plan_optimize_lazy_materialization = true to gain the benefit of lazy materialization. It is enabled by default.
Response
Consider the difference in performance with lazy materialization turned off and turned on:

How to confirm lazy materialization in the query execution plan

You can observe usage of lazy materialization for the previous query by inspecting the query’s logical execution plan using the EXPLAIN clause:
You can read the operator plan from bottom to top and observe that ClickHouse defers reading the three large String columns until after sorting and limiting.
Last modified on July 2, 2026