またひと月が過ぎ、次のリリースの時期となりました。今回は ClickHouse のオープンソース化 10 周年 と重なる特別なリリースです。
ClickHouse 26.6 は 記録破りのリリース であり、56 件の新機能 🌞、79 件のパフォーマンス最適化 🏖️、366 件のバグ修正 🍦 を含んでいます。
本リリースでは、仮想スキッピングインデックス、カスケード型リフレッシャブルマテリアライズドビュー、継続的クエリの実験的サポートなどが導入されています。
新しいコントリビューター
26.6 の新しいコントリビューターの皆さんを心から歓迎します。ClickHouse コミュニティの成長にはいつも頭が下がる思いであり、ClickHouse の人気を支えてくださる貢献に常に感謝しています。
新しいコントリビューターの方々は以下のとおりです:
Aditya Chopra, Alasdair Brown, Almaz Kunpeissov, Andriy Yakovlev, Antonio Filipovic, Asya Shneerson, Avenir Voronov, Dmitriy Borisenko, Elian Gidoni, Hanzi Jiang, Harikrishnan Prabakaran, Joe Smith, Joey Yu, Le Zhang, Lefteris Gilmaz, Maksim Dergousov, Maksim Moisiuk, Mathuranath Metivier, Minh Vu, Mohamed Abdelhalim, Mohamed Hussain, MunMunMiao, Patrick Pichler, Ramarajusairajesh, Rory Shanks, SKULLFIRE07, Saarthak Gupta, Sacheendra Talluri, Sergey Kuznetsov, Thomas Cabral, Valerii Mordovskii, Valerii Petrov, Varoon Pazhyanur, Venkata Vineel, Vinayak Joshi, Walt Ribeiro, Youssef Kadry, abdelhalim, abduldjafar, alexbakharew, andyzzhao, bernardlim, daxzel, harikrishnan94, leonard9893, linjiayu, mzitnik, ofeliacode, siwakorn.r, sugaf1204, thewisenerd, uber, uwezkhan, valerypetrov, yousefQadry, zhiqiang-hhhh
ヒント: このリストの生成方法に興味がある方は… こちら をご覧ください。
仮想スキッピングインデックス
コントリビューター: Yarik Briukhovetskyi
ClickHouse 26.6 からは、インデックスを実際に構築することなく、「このスキッピングインデックスがあったらどうなるか?」を試すことができるようになりました。
仮想インデックスは現在のセッションにのみ存在し、他のセッションからは見えず、セッションの終了時に破棄されます。
イギリスの不動産データセット で試してみましょう。検証用の行数を増やすためにパーティションを数回複製しておきます:
ALTER TABLE uk_price_paid
ATTACH PARTITION ID 'all'
FROM uk_price_paid;5 億行近くになりました:
SELECT count() FROM uk_price_paid;┌───count()─┐
│ 487239408 │ -- 487.24 million
└───────────┘
1 row in set. Elapsed: 0.006 sec.ロンドンで売買件数が最も多い地区を見つけるため、次のクエリを実行します:
SELECT district, count(), round(avg(price)) AS avgPrice
FROM uk_price_paid
WHERE town = 'LONDON'
GROUP BY ALL
ORDER BY count() DESC
LIMIT 10;┌─district────────────┬─count()─┬─avgPrice─┐
│ WANDSWORTH │ 3258048 │ 496367 │
│ LAMBETH │ 2354352 │ 402424 │
│ CITY OF WESTMINSTER │ 2164304 │ 1215976 │ -- 1.22 million
│ TOWER HAMLETS │ 2098864 │ 473783 │
│ LEWISHAM │ 2022208 │ 291688 │
│ SOUTHWARK │ 1998816 │ 462604 │
│ BARNET │ 1942384 │ 449124 │
│ GREENWICH │ 1874464 │ 316369 │
│ WALTHAM FOREST │ 1813360 │ 270709 │
│ NEWHAM │ 1706352 │ 284768 │
└─────────────────────┴─────────┴──────────┘
10 rows in set. Elapsed: 0.317 sec. Processed 487.24 million rows, 1.20 GB (1.54 billion rows/s., 3.80 GB/s.)
Peak memory usage: 894.97 KiB.town カラムに set 型スキッピングインデックスを追加することで、おそらくこのクエリのパフォーマンスを改善できます。
set 型スキッピングインデックスは、指定されたグラニュール数ごとにそのカラムの一意な値を保持します。クエリ実行時、ClickHouse はこのスキッピングインデックスの集合を参照して、特定のグラニュールをスキャンする必要があるかどうかを判断できます。
26.6 以前は、そのスキッピングインデックスを作成してテストする必要がありましたが、現在は代わりに仮想インデックスを作成できます。今回は、1 グラニュールごとにスキッピングインデックスを作成する場合と、128 グラニュールごとに作成する場合の違いを確認するため、仮想インデックスを 2 つ作成してみます:
CREATE HYPOTHETICAL INDEX town_set_10_granularity_1
ON uk_price_paid (town)
TYPE set(10)
GRANULARITY 1;
CREATE HYPOTHETICAL INDEX town_set_10_granularity_128
ON uk_price_paid (town)
TYPE set(10)
GRANULARITY 128;作成後、地区を調べるクエリの先頭に EXPLAIN WHATIF を付加します:
EXPLAIN WHATIF
SELECT district, count(), round(avg(price)) AS avgPrice
FROM uk_price_paid
WHERE town = 'LONDON'
GROUP BY ALL
ORDER BY count() DESC
LIMIT 10;このクエリを実行すると、ClickHouse はテーブルデータを読み取ってメモリ上に候補インデックスを構築し、セッションの読み取り制限やクォータに照らしてスキャン数を集計します。クエリの実行結果は以下のとおりです:
┌─explain───────────────────────────────────────────────┐
│ Baseline (after PK + partition + existing indexes): │
│ table: default.uk_price_paid │
│ parts: 3 │
│ marks: 59479 │
│ est_bytes: 831.90 MiB │
│ │
│ With town_set_10_granularity_128 (set, hypothetical): │
│ status: applicable │
│ marks: 13702 │
│ est_bytes: 191.64 MiB │
│ skip_ratio: 77.0% │
│ │
│ Estimation: │
│ source: empirical │
│ empirical_status: ok │
│ sampled_parts: 3 / 3 │
│ sampled_marks: 59479 / 118964 │
│ elapsed_us: 3826267 │
│ │
│ With town_set_10_granularity_1 (set, hypothetical): │
│ status: applicable │
│ marks: 4663 │
│ est_bytes: 65.22 MiB │
│ skip_ratio: 92.2% │
│ │
│ Estimation: │
│ source: empirical │
│ empirical_status: ok │
│ sampled_parts: 3 / 3 │
│ sampled_marks: 59479 / 118964 │
│ elapsed_us: 4283731 │
│ │
└───────────────────────────────────────────────────────┘
32 rows in set. Elapsed: 8.115 sec. Processed 974.48 million rows, 1.95 GB (120.08 million rows/s., 240.11 MB/s.)
Peak memory usage: 269.35 KiB.12 行目を見ると、128 グラニュールごとのインデックスではこのクエリに対してグラニュールの 77% がスキップされますが、25 行目では、1 グラニュールごとのインデックスによってグラニュールの 92% がスキップされることが分かります。
これにより、スキッピングインデックスを作成するかどうか、どのような設定を使用するかを決定する前に、有用な情報を得られます。
カスケード型リフレッシャブルマテリアライズドビュー
コントリビューター: Michael Kolupaev
ClickHouse 26.6 では、リフレッシャブルマテリアライズドビューの依存関係の仕組みが全面的に刷新されました。
本リリース以前も、リフレッシャブルマテリアライズドビュー間で依存関係を作成することは可能でしたが、依存する側のビューは独自のタイマーで動作したままでした。そのため、スケジュールにズレが生じるとステージ間でレイテンシが蓄積し、ビューが 1 リフレッシュサイクル分スキップされたり遅れたりすることがありました。
IMDB データを表す以下の一連のテーブルを使って設定方法を見ていきましょう:
CREATE TABLE actor_summary
(
`id` UInt32,
`name` String,
`movies` UInt16,
`avg_rank` Float32,
`genres` UInt16,
`directors` UInt16,
`updated_at` DateTime
)
ENGINE = MergeTree
ORDER BY movies;CREATE TABLE actor_rank
(
`id` UInt32,
`name` String,
`movies` UInt16,
`avg_rank` Float32,
`genres` UInt16,
`directors` UInt16,
`updated_at` DateTime
)
ENGINE = MergeTree
ORDER BY movies;CREATE TABLE actor_rank_over_time
(
`id` UInt32,
`name` String,
`avg_rank` Float32,
`as_of` DateTime
)
ENGINE = MergeTree
ORDER BY as_of;以前は、これらのテーブルに以下のようにデータを投入していました:
CREATE MATERIALIZED VIEW actor_summary_mv
REFRESH EVERY 2 MINUTES TO actor_summary AS
...CREATE MATERIALIZED VIEW actor_rank_mv
REFRESH EVERY 1 MINUTE DEPENDS ON actor_summary_mv
TO imdb.actor_rank AS
SELECT *
FROM actor_summary
WHERE movies > 10
ORDER BY avg_rank DESC
LIMIT 5;CREATE MATERIALIZED VIEW actor_rank_over_time_mv
REFRESH EVERY 1 MINUTE DEPENDS ON actor_rank_mv
APPEND
TO imdb.actor_rank_over_time AS
SELECT id, name, avg_rank, now() AS as_of
FROM actor_rank
ORDER BY avg_rank DESC
LIMIT 1;現在は、actor_summary_mv のみにタイマーを設定し、actor_rank_mv や actor_rank_over_time_mv には指定する必要がありません。そのため、以下のように記述できます:
CREATE MATERIALIZED VIEW actor_summary_mv
REFRESH EVERY 2 MINUTES TO actor_summary AS
...CREATE MATERIALIZED VIEW actor_rank_mv
REFRESH DEPENDS ON actor_summary_mv
TO imdb.actor_rank AS
SELECT *
FROM actor_summary
WHERE movies > 10
ORDER BY avg_rank DESC
LIMIT 5;CREATE MATERIALIZED VIEW actor_rank_over_time_mv
REFRESH DEPENDS ON actor_rank_mv
APPEND
TO actor_rank_over_time AS
SELECT id, name, avg_rank, now() AS as_of
FROM imdb.actor_rank
ORDER BY avg_rank DESC
LIMIT 1;ALTER TABLE … ADD ENUM VALUES
コントリビューター: Ilya Golshtein
uk_price_paid テーブル内の Enum カラムを見つけるために、次のクエリを実行できます:
SELECT name, type
FROM system.columns
WHERE table = 'uk_price_paid'
AND database = 'default'
AND type LIKE 'Enum%'
FORMAT Vertical;Row 1:
──────
name: type
type: Enum8('other' = 0, 'terraced' = 1, 'semi-detached' = 2, 'detached' = 3, 'flat' = 4)
Row 2:
──────
name: duration
type: Enum8('unknown' = 0, 'freehold' = 1, 'leasehold' = 2)ClickHouse 26.6 より前は、新しい Enum 値を追加する際に既存の値もすべて指定する必要がありました:
ALTER TABLE uk_price_paid
MODIFY COLUMN type Enum8(
'other' = 0,
'terraced' = 1,
'semi-detached' = 2,
'detached' = 3,
'flat' = 4,
'royal' = 5
);現在は、ADD ENUM VALUES 構文を使用して新しい値を追加できるようになりました:
ALTER TABLE uk_price_paid
MODIFY COLUMN type
ADD ENUM VALUES('royal' = 5);Enum カラムを表示するクエリを再実行すると、次のようになります:
Row 1:
──────
name: type
type: Enum8('other' = 0, 'terraced' = 1, 'semi-detached' = 2, 'detached' = 3, 'flat' = 4, 'royal' = 5)
Row 2:
──────
name: duration
type: Enum8('unknown' = 0, 'freehold' = 1, 'leasehold' = 2)
2 rows in set. Elapsed: 0.006 sec.CLI 内での help コマンド
コントリビューター: Alexey Milovidov
ClickHouse の作業に集中していてドキュメントを参照したいとき、CLI から離れてドキュメントを検索したり AI エージェントに答えを求めたりする必要はありません。代わりに、help に続けてトピック名を入力すれば、インラインでドキュメントを確認できます。
help Geometry;GEOMETRY (Data Type)
─────────────────────────────────────────────────────────────────────────────────────────
Alias of Geometry.
Geometry (Data Type)
─────────────────────────────────────────────────────────────────────────────────────────
Geometry is a Variant type that can hold any of the geometric data types: Point,
LineString, MultiLineString, Polygon, MultiPolygon, or Ring.
Syntax
Geometry
Related: Pointこれは新しい system.documentation テーブルによって提供されており、直接クエリを実行することも可能です:
SELECT type, count()
FROM system.documentation
GROUP BY type
ORDER by count() DESC
LIMIT 10;┌─type───────────────┬─count()─┐
│ Function │ 1593 │
│ Setting │ 1549 │
│ Server Setting │ 412 │
│ MergeTree Setting │ 316 │
│ Aggregate Function │ 197 │
│ Data Type │ 140 │
│ Format │ 109 │
│ Table Engine │ 79 │
│ Table Function │ 66 │
│ Dictionary Layout │ 19 │
└────────────────────┴─────────┘
10 rows in set. Elapsed: 0.019 sec. Processed 4.54 thousand rows, 4.36 MB (240.42 thousand rows/s., 230.69 MB/s.)
Peak memory usage: 6.18 MiB.clickhouse-local のサーバー化
コントリビューター: Alexey Milovidov
clickhouse-local はアドホックなデータ分析を行うための頼れるツールですが、ClickHouse インスタンスを外部ツールに接続したい場合、これまでは簡単ではありませんでした。
26.6 からは、clickhouse-local で即座に接続をリッスンできるようになりました:
SYSTEM START LISTEN TCP;
SYSTEM START LISTEN HTTP;あとは ClickHouse Server を実行しているときと同様に、ClickHouse Client を使って接続できます:
./clickhouse client -mnClickHouse client version 26.7.1.22 (official build).
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 26.7.1.SHOW TABLES;┌─name──────────┐
│ uk_price_paid │
└───────────────┘
1 row in set. Elapsed: 0.002 sec.また、http://localhost:8123 にアクセスして Web UI を開くこともできます。ここから Schema visualizer をクリックすると、データベースの依存関係グラフを描画する新しい UI を確認できます。これにはテーブル、マテリアライズドビュー、辞書が含まれます。今回の例ではテーブルが 1 つしかないため、あまり見応えはありません:

皆さんの環境ではもっと見栄えのするものになるはずです!
作業が終わったら、それらのポートでのリッスンを簡単に停止できます:
SYSTEM STOP LISTEN TCP;
SYSTEM STOP LISTEN HTTP;クエリ起動の軽量化・高速化
コントリビューター: Raúl Marín, Dmitry Novik, Max Justus Spransy, Azat Khuzhin
26.6 では、単純なクエリにおけるクエリごとのオーバーヘッドを大幅に削減する一連の改善が行われました。
特に深くネストされたクエリの解析が効率化されました。以下の(不必要に複雑な)クエリを実行してみましょう:
SELECT * FROM (SELECT * FROM (SELECT * FROM (SELECT * FROM (
SELECT * FROM (SELECT * FROM (SELECT * FROM (SELECT * FROM (
SELECT * FROM (SELECT * FROM (SELECT * FROM (SELECT * FROM (
SELECT * FROM (SELECT * FROM (SELECT * FROM (SELECT * FROM (
SELECT * FROM (SELECT * FROM (SELECT * FROM (
SELECT * FROM uk_price_paid LIMIT 10
)))))))))))))))))));26.5 での実行結果:
10 rows in set. Elapsed: 0.098 sec.
10 rows in set. Elapsed: 0.102 sec.
10 rows in set. Elapsed: 0.100 sec.26.6 での実行結果:
10 rows in set. Elapsed: 0.030 sec.
10 rows in set. Elapsed: 0.036 sec.
10 rows in set. Elapsed: 0.050 sec.26.5 での最速タイムが 98 ms だったのに対し、26.6 では 30 ms となり、約 3 倍の改善となりました。
継続的クエリ
コントリビューター: Mikhail Artemenko
実験的モードとしてストリーミングクエリも導入されました。STREAM を付加することで、終了しないクエリを記述できるようになりました。新しい行が挿入されるたびに、クエリはそれを出力し続けます。
この機能を有効にするには、以下の設定を使用します:
SET enable_streaming_queries = 1;これにより、処理をブロックしたまま新しい行をストリーミングし続ける以下のクエリを記述できます:
SELECT id, msg
FROM live_events STREAM;live_events に新しい行が追加されると、上記のクエリによって返されます。
この機能は、カーソルを使用したより高度なモードでも利用できます:
SELECT _block_number AS bn, _block_offset AS bo, id, msg
FROM events STREAM
CURSOR {'all': {'block_number': 2, 'block_offset': 0}};PNG 出力フォーマット
コントリビューター: Maksim Dergousov
26.6 では PNG 出力フォーマットが導入され、クエリ結果を画像としてレンダリングできるようになりました。1 行が 1 ピクセル(r, g, b または v)に対応し、ピクセル座標(x, y)は暗黙的または明示的に定義されます。たとえば以下のようになります:
WITH number DIV 1024 AS y, number MOD 1024 AS x,
L2Norm((x - 512, y - 512)) / 512 AS radius, 60 AS stripe_size,
round((atan2(x - 512, y - 512) / pi() * 180 + exp(radius) * 90)
/ stripe_size) * stripe_size AS alpha,
radius <= 1 ? abs(1 - (radius - 0.5) * (radius - 0.5) * 4) : 0 AS a,
colorOKLCHToSRGB((0.7, 0.15, alpha)) AS rgb
SELECT rgb.1::UInt8 AS r, rgb.2::UInt8 AS g, rgb.3::UInt8 AS b, a
FROM numbers(1048576) FORMAT PNG
この機能を活用して、Alexey はすべて ClickHouse の SQL クエリとして記述され、PNG に直接レンダリングするパストレーサー RayTracer を作成しました。
地理空間機能の改善
コントリビューター: Mark Needham, Alexey Milovidov, Saarthak Gupta
ClickHouse 26.6 からは、GeoJSON の feature collection を読み込むと、feature ごとに 1 行が生成されるようになりました:
SELECT id, properties.name, toTypeName(geometry)
FROM file('places.geojson', GeoJSON);| id | properties.name | geometry |
|---|---|---|
| 1 | London | Geometry (Point) |
| 2 | square | Geometry (Polygon) |
Point、LineString、MultiLineString、Polygon、MultiPolygon がすべてネイティブでサポートされています。
また、新しい MVT 関数を使用して、ClickHouse から直接マップタイルを配信できるようになりました。
経度・緯度をタイルのピクセル空間に射影:
SELECT MVTEncodeGeom((13.37, 52.52)::Point, 10, 550, 335);┌─MVTEncodeGeo⋯, 550, 335)─┐
│ (124,3384) │
└──────────────────────────┘グループのジオメトリを 1 つのバイナリタイルに集約:
SELECT MVTEncode(geom_in_tile_space) FROM ...;WHERE 句で使用するタイルのバウンディングボックス:
SELECT MVTBoundingBox(12, 1205, 2557);┌─MVTBoundingBox(12, 1205, 2557)───┐
│ { ↴│
│↳ "min_lon": -74.091796875, ↴│
│↳ "min_lat": -40.84706035607121,↴│
│↳ "max_lon": -74.00390625, ↴│
│↳ "max_lat": -40.78054143186031 ↴│
│↳} │
└──────────────────────────────────┘Point、Line、Polygon のジオメトリタイプがサポートされています。
aiEmbed
コントリビューター: George Larionov
26.6 では、ClickHouse で利用可能な実験的 AI 関数のコレクションに aiEmbed が追加されました。
Ollama を使ってローカルで利用する方法を見てみましょう。まず、qwen3-embedding モデルを使用し、Ollama の埋め込み API エンドポイントを指す名前付きコレクションを設定します:
CREATE NAMED COLLECTION ollama_credentials AS
provider = 'openai',
endpoint = 'http://localhost:11434/v1/embeddings',
model = 'qwen3-embedding',
api_key = 'ollama';次に、AI 関数と認証情報を設定します:
SET allow_experimental_ai_functions = 1;
SET ai_function_credentials = 'ollama_credentials';これで aiEmbed 関数を呼び出すことができます:
SELECT arraySlice(aiEmbed('Hello world'), 1, 10)
FORMAT Vertical;Row 1:
──────
arraySlice(a⋯d'), 1, 10): [0.02529167,0.017939178,-0.017299227,-0.021381723,0.017130155,-0.025205782,-0.028271621,0.011541649,-0.02053676,0.021490935]
1 row in set. Elapsed: 0.192 sec.量子化関数
コントリビューター: Alexey Milovidov
26.6 リリースには、埋め込みの構成要素を 8 ビット以下に圧縮するスカラーコーデックも追加されました:
SELECT quantizeBFloat16ToInt8(1.5::BFloat16);┌─quantizeBFlo⋯BFloat16'))─┐
│ 107 │
└──────────────────────────┘WITH quantizeBFloat16ToInt8(1.5::BFloat16) AS quantized
SELECT dequantizeInt8ToBFloat16(quantized);┌─dequantizeIn⋯(quantized)─┐
│ 1.5 │
└──────────────────────────┘この関数を使用することで、ベクトルインデックスを 4 分の 1(またはそれ以上)に縮小し、類似検索のコストを削減できます。
ワークロード向けメモリ予約
コントリビューター: Sergei Trifonov
すでに CPU、I/O、同時実行数を管理しているワークロードスケジューラーが、ClickHouse 26.6 からメモリも管理できるようになりました。
まずリソースを作成します:
CREATE RESOURCE memory (MEMORY RESERVATION);次に、各種ワークロードを定義できます:
CREATE WORKLOAD all;
CREATE WORKLOAD prod IN all SETTINGS max_memory = '100G';
CREATE WORKLOAD reports IN all SETTINGS max_memory = '20G';
CREATE WORKLOAD vasya IN reports SETTINGS weight = 1;
CREATE WORKLOAD petya IN reports SETTINGS weight = 2;クエリを実行する際は、次のようにしてワークロードへとルーティングできます:
SELECT …
SETTINGS workload = 'prod';


