メインコンテンツへスキップ
メインコンテンツへスキップ

遅延マテリアライゼーション

この記事では、遅延マテリアライゼーションの仕組みと、ClickHouse の I/O 最適化スタック全体の中での位置付けについて説明します。 また、遅延マテリアライゼーションによってクエリパフォーマンスがどのように向上するかを示す実例も紹介します。

バージョン 25.4 以降で利用可能

遅延マテリアライゼーションは ClickHouse のバージョン 25.4 で導入され、デフォルトで有効になっています。

Overview

長年にわたり、ClickHouse は I/O を積極的に削減するため、一連の階層的な最適化を導入してきました。 これらの手法は、その高速性と効率性を支える基盤となっています。

OptimizationDescription
Columnar storageクエリに不要なカラム全体をスキップできるほか、類似した値をまとめることで高い圧縮率を実現し、データ読み込み時の I/O を最小化します。
Sparse primary indexes | secondary data-skipping indexes | projectionsインデックス付きカラム に対するフィルタと一致する可能性がある granules(行ブロック)を特定し、不要なデータを刈り込みます。これらの手法は granule レベルで動作し、個別にも組み合わせても利用できます。
PREWHEREインデックスがない カラムに対するフィルタについてもマッチを確認し、本来であれば読み込まれてから破棄されるデータを早期にスキップします。索引によって選択された granule をさらに絞り込む形でも、独立しても動作し、すべてのカラムフィルタに一致しない行をスキップすることで granule の刈り込みを補完します。
Query condition cacheどの granule が前回すべてのフィルタにマッチしたかを記憶することで、繰り返し実行されるクエリを高速化します。これにより、たとえクエリの形が変わっても、マッチしなかった granule の読み取りとフィルタリングをスキップできます。

上記の I/O 最適化は読み取るデータ量を大きく削減できますが、それでもなお、WHERE 句を通過した行については、ソートや集約、LIMIT のような操作を実行する前に、すべてのカラムを読み込むことを前提としています。 しかし、一部のカラムはもっと後になるまで不要な場合や、WHERE 句を通過したにもかかわらず、結局まったく参照されないデータも存在し得ます。 そこで登場するのが lazy materialization です。これは I/O 最適化スタックを完成させる、直交する拡張機能です。

  • 索引と PREWHERE を組み合わせることで、WHERE 句のカラムフィルタに一致する行だけが処理されるようになります。
  • Lazy materialization はこれをさらに発展させ、実際にクエリ実行プランで必要になるまでカラムの読み取りを遅延させます。 フィルタリング後であっても、ソートのような次の処理に必要なカラムだけが即座に読み込まれます。 その他のカラムは後回しにされ、LIMIT の影響により、多くの場合は最終結果を生成するのに十分な一部だけが読み込まれます。 これにより、lazy materialization は Top N クエリに対して特に強力であり、最終的な結果には、しばしば巨大なカラムからごく少数の行だけがあれば足りるようになります。

実例での説明

レイジー・マテリアライゼーションについて詳しく知るには、ブログ記事 "ClickHouse gets lazier (and faster): Introducing lazy materialization" を強く推奨します。以下の例は前述のブログ記事から引用したもので、レイジー・マテリアライゼーションにより、ある ClickHouse クエリが 219 秒からわずか 139 ミリ秒(1576 倍の高速化)まで短縮できる様子を示しています。

インデックスと PREWHERE の恩恵を受けるには、クエリにはフィルターが必要です。インデックスには主キーのカラムに対するフィルターが、PREWHERE には任意のカラムに対するフィルターが必要になります。 レイジー・マテリアライゼーションはその上にきれいに積み重ねられますが、前述の他の最適化と異なり、カラムフィルターがまったく無いクエリでも高速化することができます。

次の例のクエリを考えてみます。このクエリは、日付、商品、評価、検証ステータスに関係なく、Amazon レビューのうち「役に立った」投票数が最も多いものを探し、そのタイトル、見出し、本文とともに上位 3 件を返します。

まずは、レイジー・マテリアライゼーションを無効にして(query_plan_optimize_lazy_materialization を使用し)、クエリを実行します(ファイルシステムキャッシュはコールドの状態):

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;
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...

# highlight-start
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.
# highlight-end

次に、(今回もファイルシステムキャッシュをコールドな状態にして)クエリを再実行しますが、今度はレイジーマテリアライゼーションを有効にします:

SELECT
    helpful_votes,
    product_title,
    review_headline,
    review_body
FROM amazon.amazon_reviews
ORDER BY helpful_votes DESC
LIMIT 3
FORMAT Vertical
SETTINGS
-- highlight-next-line
query_plan_optimize_lazy_materialization = true;
ヒント

通常は、レイジーマテリアライゼーションの利点を得るために query_plan_optimize_lazy_materialization = true を明示的に設定する必要はありません。 これはデフォルトで有効になっています。

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...

# highlight-start
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.
# highlight-end

遅延マテリアライゼーションを無効にした場合と有効にした場合とで、パフォーマンスがどのように変わるかを見てみましょう。

メトリックLazy materialization オフLazy materialization オン改善度
経過時間219.071 秒0.139 秒約1576×高速
読み取りデータ量71.38 GB1.81 GB約40×少ない
ピークメモリ使用量1.11 GiB3.80 MiB約300×少ない

クエリ実行プランでレイジーマテリアライゼーションを確認する方法

EXPLAIN 句を使用してクエリの論理実行プランを確認すると、先ほどのクエリでレイジーマテリアライゼーションが利用されていることを確認できます。

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;
...
# highlight-next-line
Lazily read columns: review_headline, review_body, product_title
  Limit
    Sorting
      ReadFromMergeTree

オペレータープランは下から上へ読み進めることができ、ClickHouse がソートと LIMIT の処理が終わるまで、大きな 3 つの String 型カラムの読み出しを遅延させていることが確認できます。