ClickHouseがクエリを並行して実行する方法
ClickHouseはスピードのために構築されています。それは、利用可能なすべてのCPUコアを使用し、処理レーンにデータを分散させ、しばしばハードウェアをその限界に近づけて、クエリを高度に並行して実行します。
このガイドでは、ClickHouseのクエリ並行性がどのように機能し、大規模なワークロードでのパフォーマンスを向上させるためにそれを調整または監視する方法について説明します。
主要な概念を説明するために、uk_price_paid_simpleデータセットに対する集約クエリを使用します。
手順: ClickHouseが集約クエリを並行化する方法
ClickHouseが ① プライマリキーにフィルタをかけた集約クエリを実行すると、② プライマリインデックスがメモリに読み込まれ、③ どのグラニュールを処理する必要があるか、どれを安全にスキップできるかを特定します:

処理レーンにまたがる作業の分散
選択されたデータは、n
並行処理レーンに動的に分散され、データはブロックごとにストリームされ、処理され、最終結果にまとめられます:

n
の並行処理レーンの数は、max_threads設定によって制御され、デフォルトではサーバー上でClickHouseが利用できるCPUコアの数に一致します。上記の例では、4
コアを仮定しています。
8
コアのマシンでは、クエリ処理のスループットは概ね2倍になります(ただし、メモリ使用量もそれに応じて増加します)。より多くのレーンが並行してデータを処理するためです:

効率的なレーン分配は、CPUの利用率を最大化し、総クエリ時間を短縮するための鍵です。
シャードテーブル上のクエリ処理
テーブルデータが複数のサーバーにシャードとして分散されている場合、各サーバーはそのシャードを並行して処理します。各サーバー内では、ローカルデータが上記で説明したように並行処理レーンを使用して処理されます:

最初にクエリを受信したサーバーは、シャードからすべてのサブ結果を集約し、最終的なグローバル結果に統合します。
シャード間でクエリ負荷を分散させることで、特に高スループット環境において並行性の水平スケーリングを可能にします。
ClickHouse Cloudでは、同じ並行性が並行レプリカを通じて実現されており、これはシャードが共有なしのクラスターで機能するのと類似しています。各ClickHouse Cloudレプリカは、ステートレスなコンピュートノードであり、並行してデータの一部を処理し、独立したシャードのように最終結果に貢献します。
クエリ並行性の監視
これらのツールを使用して、クエリが利用可能なCPUリソースを完全に活用しているかどうかを確認し、そうでない場合に診断します。
私たちは59のCPUコアを持つテストサーバーでこれを実行しており、ClickHouseはそのクエリ並行性を完全に示すことができます。
例のクエリがどのように実行されるかを観察するために、ClickHouseサーバーに集約クエリ中にすべてのトレースレベルのログエントリを返すように指示できます。このデモのために、クエリの述語を削除しました—そうでなければ、3つのグラニュールしか処理されず、ClickHouseが複数の並行処理レーンを利用するには不十分なデータとなります:
私たちは次のことがわかります
- ① ClickHouseは3,609グラニュール(トレースログにマークとして表示される)を3つのデータ範囲から読み取る必要があります。
- ② 59のCPUコアを使用して、これは59の並行処理ストリームに分配されます—レーンごとに1つです。
また、EXPLAIN句を使用して集約クエリの物理演算子プラン—通称「クエリパイプライン」を検査できます:
注意: 上記の演算子プランは、下から上へ読み取ってください。各行は、ストレージからデータを読み取るのを開始点とし、最終的な処理ステップで終了します。× 59
でマークされた演算子は、59の並行処理レーンにわたって重複のないデータ領域で同時に実行されます。これはmax_threads
の値を反映し、クエリの各ステージがCPUコアにわたってどのように並行化されているかを示しています。
ClickHouseの埋め込まれたWeb UI(/playエンドポイントで利用可能)は、上記の物理プランをグラフィカルな視覚化としてレンダリングできます。この例では、視覚化をコンパクトに保つため、max_threads
を4
に設定し、4つの並行処理レーンのみを表示します:

注意: 視覚化を左から右に読み取ってください。各行は、データをブロックごとにストリーミングし、フィルタリング、集約、最終処理ステップなどの変換を適用する並行処理レーンを表しています。この例では、max_threads = 4
設定に対応する4つの並行レーンを確認できます。
処理レーン間の負荷分散
上記の物理プランのResize
演算子は、処理レーン間でデータブロックストリームを再分割し再配布して均等に活用されるようにします。この再バランス処理は、データ範囲がクエリ述語に一致する行数で異なる場合には特に重要です。さもなければ、一部のレーンが過負荷になり、他のレーンがアイドル状態になるかもしれません。作業を再分配することで、より早いレーンが遅いものを効果的に助け、全体のクエリ実行時間を最適化します。
なぜmax_threadsは常に尊重されないのか
上記のように、n
の並行処理レーンの数は、デフォルトでサーバー上でClickHouseが利用できるCPUコア数に一致するmax_threads
設定によって制御されます:
ただし、処理のために選択したデータ量に応じてmax_threads
値が無視される場合があります:
上記の演算子プランの抜粋に示されているように、max_threads
が59
に設定されているにもかかわらず、ClickHouseはデータのスキャンに30の同時ストリームしか使用していません。
それではクエリを実行してみましょう:
出力で示されているように、クエリは2.31百万行を処理し、13.66MBのデータを読み取りました。これは、インデックス分析フェーズ中にClickHouseが282グラニュールを処理のために選択したためです。各グラニュールには8,192行が含まれ、合計で約2.31百万行となります:
設定されたmax_threads
値にかかわらず、ClickHouseは十分なデータがない場合追加の並行処理レーンを割り当てません。max_threads
の「max」は上限を示すものであり、使用されるスレッド数が保証されるわけではありません。
「十分なデータ」とは何かは、主にそれぞれの処理レーンが処理すべき行数の最小限(デフォルトは163,840)と最小バイト数(デフォルトは2,097,152)で決定されます:
共有なしのクラスター用:
共有ストレージがあるクラスター用(例:ClickHouse Cloud):
- merge_tree_min_rows_for_concurrent_read_for_remote_filesystem
- merge_tree_min_bytes_for_concurrent_read_for_remote_filesystem
さらに、読み取りタスクサイズには厳しい下限があり、以下で制御されています:
これらの設定を本番環境で変更することはお勧めしません。これらは、max_threads
が常に実際の並行性レベルを決定しない理由を示すためにのみここに示されています。
デモ目的で、これらの設定を上書きして最大の同時実行性を強制するために物理プランを検査しましょう:
これでClickHouseはデータをスキャンするために59の同時ストリームを使用し、設定されたmax_threads
に完全に従います。
これは、小さなデータセットに対するクエリにおいて、ClickHouseが意図的に同時実行性を制限することを示しています。設定の上書きはテスト用のみ使用し、本番環境では利用しないでください。このような変更は非効率的な実行やリソース競合を引き起こす可能性があります。
主なポイント
- ClickHouseは
max_threads
に関連付けられた処理レーンを使用してクエリを並行化します。 - 実際のレーンの数は、処理のために選択されたデータのサイズに依存します。
EXPLAIN PIPELINE
とトレースログを使用してレーン使用状況を分析します。
さらなる情報を見つけるには
ClickHouseがクエリを並行して実行する方法や、スケールアップ時に高性能を達成する方法についてさらに深く探求したい場合は、以下のリソースを参照してください:
-
クエリ処理層 – VLDB 2024 論文 (Web版) - ClickHouseの内部実行モデルに関する詳細な説明で、スケジューリング、パイプライン、演算子設計を含みます。
-
部分集約状態の説明 - 部分集約状態が処理レーンの並行実行を効率的に可能にする方法に関する技術的な深掘り。
-
ClickHouseのクエリ処理ステップを詳細に解説したビデオチュートリアル: