1. はじめに
ClickHouse が 2026年7月10日、ADBC(Arrow Database Connectivity)という新しいドライバを公式発表しました1。Apache Arrow はカラム指向のメモリ形式で、複数の言語・ツールが同じバイト列をコピーせずにやり取りできる規格です。ADBC はこの Arrow のための共通接続 API で、ClickHouse 版ドライバは Rust 製・HTTP 経由、本記事執筆時点のバージョンは 0.1.0(アルファ版)です2。公式ブログは「クエリ結果が Arrow のまま届き、途中で行形式への変換を経由しない」ことを売りにしています1。
ただ、この「Arrow のまま届く」自体は ADBC の専売ではありません。Python の ClickHouse クライアントである clickhouse-connect には、以前から query_arrow というメソッドがあり、公式 Docs にも「ClickHouse の Arrow 形式を直接使う」と明記されています3。つまり Python で Arrow のまま受け取りたいだけなら、ADBC を待つ必要はなかったわけです。であれば、ADBC が登場して何が変わるのか。公式ブログには設計の説明はあっても、ベンチマークの数値が載っていません。
そこで今回は、ClickHouse からデータを取得する 6 通りの方法を実測し、DataFrame が手元に届くまでの時間を比べました。あわせて、Arrow に変換したときにどの型が届いてどの型が落ちるかも確認しています。
比較したのは次の 6 つです。うち query_arrow_stream は、検証を進める中で見つけて追加実測した方法です(6.2 章)。
| 方法 | 実装 | 内容 |
|---|---|---|
query_df |
clickhouse-connect | ClickHouse 独自の通信形式から pandas へ変換する、以前からの定番 |
query_arrow |
clickhouse-connect | サーバの Arrow 形式をそのまま pyarrow.Table として受け取る |
query_df_arrow |
clickhouse-connect | Arrow 経由で pandas へゼロコピーに近い変換を行う |
query_arrow_stream |
clickhouse-connect | サーバの ArrowStream 形式をレコードバッチで受け取る(6.2 章で追加実測) |
| ADBC |
adbc_driver_manager + ClickHouse 公式ドライバ |
今回の主役 |
| JSONEachRow | HTTP に FORMAT JSONEachRow を指定 |
返ってきた JSON テキストをそのまま pandas に読み込む方法(参考値) |
サーバーがどの形式でデータを送り出し、クライアント側で何を経由して pandas / polars(polars は Rust 製の DataFrame ライブラリ)に届くかを図にすると次のとおりです。query_arrow ・query_arrow_stream ・ADBC の 3 つは途中に pyarrow.Table を挟むため、「Arrow が届くまで」と「DataFrame への変換」を分けて計測できます。
結論先出し
-
query_dfを基準(1.00)とすると、ADBC は 100万行で 0.40 倍、4,327万行(全件)では 0.22 倍と、規模が大きいほど速くなる - ただしこの速さは ADBC 固有のものではない。差の主な原因はサーバー側の出力形式で、ADBC が使う
ArrowStream形式は行数にほぼ比例して処理時間が伸びるのに対し、query_arrowが使うArrow形式は行数の増加より速いペースで遅くなる(1,000万行→4,327万行で行数 4.3 倍に対し処理時間 7.4 倍) - 同じ
ArrowStreamは clickhouse-connect のquery_arrow_streamでも要求でき、追加実測では ADBC と同水準の速さが出た。ClickHouse Cloud 相手のリモート実測でもこの優位は残り、圧縮の有無は今回のデータでは差がほぼ出なかった - Arrow から pandas への変換速度にも経路間で差があり、4,327万行では ADBC が
query_arrowよりかなり速く変換できていた。ただし届いた Arrow テーブルのスキーマ・チャンク構成は完全に同一だったため、残る違いはパーサ実装(clickhouse-connect は Python、ADBC は Rust)にあると考えられる - JSON 型(ClickHouse のネイティブ JSON 型)は
query_arrow・query_df_arrow・ADBC のいずれでも取得できない。3 経路とも同じサーバ側エラーで落ちるため、ADBC 固有の制約ではなくサーバの Arrow 出力機能そのものの制約だと分かった - JSONEachRow の経路は 1,000万行の取得で実行できなくなった。JSON テキストのパース時にメモリを使い切ったためで、単に遅いのではなく実行自体ができない
順を追って見ていきます。
2. 検証環境
| 項目 | 内容 |
|---|---|
| ClickHouse サーバー | Docker コンテナ clickhouse/clickhouse-server:26.7(26.7.1.1315) |
| ホスト | Windows 11 Pro、Docker Desktop |
| Python | 3.12.0(Windows ネイティブ) |
| クライアントライブラリ | clickhouse-connect 1.5.0 / pyarrow 25.0.0 / pandas 3.0.5 / polars 1.43.0 / adbc-driver-manager 1.11.0 / requests 2.34.2 |
| ADBC ドライバ | ClickHouse 公式ドライバ 0.1.0(dbc コマンドで導入) |
| データ | cell_towers(ClickHouse 公式サンプルデータセット4)43,276,150 行、14 列 |
| リモート追試 | ClickHouse Cloud(AWS ap-northeast-1、小型サービス、26.2.1.525)。6.4 章で使用 |
サーバーはローカルの Docker コンテナに置き、ホストからのみ接続できるようにしています。ネットワークの帯域や遅延の影響を切り離し、クライアント側の変換コストを比較の主役にするためです。この前提が結果をどう左右するかは 6.4 章で扱います。
3. ADBC ドライバの導入と中身
3.1. 導入と接続
dbc という配布ツールでドライバを導入します。今回の検証は Windows で実施しました。
# Windows(PowerShell)
irm https://dbc.columnar.tech/install.ps1 | iex
dbc install clickhouse
# macOS / Linux(公式ブログ記載のコマンド。今回は未検証)
curl -LsSf https://dbc.columnar.tech/install.sh | sh
dbc install clickhouse
Python からは adbc_driver_manager の DB-API 経由で接続します。README に載っている接続オプション(Uri / Username / Password)2 を db_kwargs 引数に小文字の名前で指定します。次のコードで接続できました。
import adbc_driver_manager.dbapi as dbapi
# 接続オプションは小文字(uri / username / password)で渡す
conn = dbapi.connect(
driver="clickhouse",
db_kwargs={"uri": "http://localhost:8123", "username": "default", "password": ""},
)
cur = conn.cursor()
cur.execute("SELECT version()")
table = cur.fetch_arrow_table()
fetch_arrow_table() で pyarrow.Table が返ります。ここまでは README の想定どおりで、Windows・WSL の切り替えも不要でした。
3.2. 実際にサーバへ何を送っているか
ADBC は Python の接続オプションから query_id(サーバ側ログと突き合わせるための識別子)や圧縮の有無を指定する手段がありません。実際に何を送っているかを見るため、ClickHouse サーバとの間に一時的な TCP の中継役を挟んで、生の HTTP リクエストを確認しました。
POST /?default_format=ArrowStream&compress=1&output_format_arrow_compression_method=none
&query_id=query_lfeb7cLvSKHiHv17&session_id=session_R3G946LP1N1m7u6X HTTP/1.1
user-agent: clickhouse-ext-arrow/0.1.0 adbc_clickhouse/0.1.0 clickhouse-rs/0.15.1 (lv:rust/1.89.0; os:windows)
分かったことが 2 つあります。1 つは要求している出力形式です。query_arrow が使う FORMAT Arrow ではなく、FORMAT ArrowStream を指定していました。両者の違いは 6.1 章で扱います。もう 1 つは圧縮で、compress=1(ClickHouse 独自の内部圧縮形式で、標準の HTTP 圧縮とは別物です5)を常に固定で送っていました。Python 側の接続オプションに無効化する設定はなく、URI にパラメータを足して試しても上書きされませんでした。
output_format_arrow_compression_method=none も同時に指定されており、こちらは Arrow データそのものの圧縮(lz4_frame / zstd / none から選べる設定6)を無効化する指定です。compress=1 は別レイヤーの圧縮で、両方を併用しても二重には圧縮されていません。
query_arrow 側は圧縮を無効化して揃えています(compress=False)。100万行を取得したときの実際の送信バイト数を比べると、query_arrow が 29,136,988 バイト、ADBC が 29,079,811 バイトで、その差は 0.2% ほどでした。ADBC だけ圧縮が有効という条件差はあるものの、cell_towers(緯度経度など Float64 が多いデータ)ではこの規模の差にしかなっていません。
4. 型マッピングの境界
公式ブログは「すべての Arrow 型が ClickHouse の型に対応するわけではない」と述べ、ORM のように行を個々のオブジェクトへマップする用途には既存クライアントを勧めています1。どこまでが対応していてどこから外れるのかを確かめるため、代表的な 25 型を集めた小さなテーブル(Memory エンジン、各型 3 行)を作り、query_arrow ・query_df_arrow ・ADBC それぞれで取得しました。
25 型のうち、注目すべきものを抜粋します。
| ClickHouse の型 |
query_df の pandas dtype |
Arrow 経由(3 経路とも同一) |
|---|---|---|
| UInt8 / Int32 / Float64 | uint8 / int32 / float64 | 同名の Arrow 型に一致 |
| Decimal(38,10) | Decimal オブジェクト | decimal128(38, 10)。桁数の欠落なし |
| FixedString(16) | NUL 埋めの bytes | fixed_size_binary[16]。パディングも一致 |
| LowCardinality(String) | string | string(辞書エンコードのまま届かず、プレーンな文字列に展開される) |
| DateTime(タイムゾーンなし) | Timestamp | uint32(Unix 秒の生値。timestamp 型にならない) |
| DateTime64(3, 'Asia/Tokyo') | tz 付き Timestamp | timestamp[ms, tz=Asia/Tokyo]。タイムゾーンを含め一致 |
| Enum8 | ラベル文字列 | int8(ラベルに解決されない整数コード) |
| IPv4 / IPv6 | IPv4Address / IPv6Address | uint32 / fixed_size_binary[16](IP としての型情報は失われる) |
| UUID | UUID オブジェクト | Arrow の拡張型経由で UUID オブジェクトに解決 |
| JSON | dict | エラー(後述) |
query_arrow ・query_df_arrow ・ADBC の 3 経路は、25 型のすべてで届く Arrow 型・値が完全に一致しました。差が出たのは query_df との間だけです。Enum8 はラベルへ解決されず整数コードのまま届きます。タイムゾーンなしの DateTime は Arrow の timestamp 型にすらならず、生の Unix 秒になります。IPv4 / IPv6 も IP アドレスとしての型情報を失い、数値やバイト列として届きます。Arrow 経由で受け取るアプリ側は、これらを自分で変換する必要があります。
逆に言えば、Arrow にしたからといって型変換が常に必要になるわけではありません。数値・文字列・Decimal・日付・配列・Map など大半の型はそのまま使える形で届き、変換が要るのは Enum8 やタイムゾーンなしの DateTime、IPv4 / IPv6 といった一部の型に限られます。
JSON 型だけは 3 経路とも同じエラーで失敗しました。
Code: 48. DB::Exception: Method getDataAt is not supported for
Object(max_dynamic_paths=1024, max_dynamic_types=32):
While executing ArrowIPCBlockOutputFormat. (NOT_IMPLEMENTED)
query_arrow は FORMAT Arrow、ADBC は FORMAT ArrowStream と異なる形式を使っているのに、エラーメッセージも内部処理の経路(ArrowIPCBlockOutputFormat)も同じでした。これは ADBC 固有の制約ではなく、ClickHouse サーバの Arrow 出力機能自体が JSON 型に未対応という、サーバ側の制約だと切り分けられます。公式ブログのロードマップにも、JSON 対応は Arrow 側の標準的なシリアライズ形式が定まるのを待っている段階だと書かれており7、この切り分けと矛盾しません。JSON 列を除けば同じテーブルから他の列だけを取得することはでき、テーブル単位ではなく列単位の制約であることも確認しています。
5. 転送ベンチ
5.1. 計測の設計
この章では、6 つの方法のうち query_arrow_stream を除く 5 つを測ります(query_arrow_stream は検証の途中で見つけた方法のため、6.2 章で同じ条件の追加実測として扱います)。同じ cell_towers から、行数を変えた 3 つのスケール(100万行・1,000万行・全件 4,327万行)で、5 つの方法それぞれの DataFrame 到達時間を測りました。1 回のスケールにつき、ウォームアップ 1 ラウンドを捨てたあと 5 ラウンドを計測し、ラウンドの中では 5 つの方法を交互に実行してキャッシュの温まり方を揃えています。クライアント側は perf_counter() で区間ごとの時間を測り、サーバー側は ClickHouse の system.query_log から同じクエリの実行時間・送信バイト数を突き合わせました。
query_arrow と ADBC は Arrow テーブルが届くまでと、そこから pandas / polars へ変換するまでを分けて計測しています。query_df ・query_df_arrow ・JSONEachRow の 3 方法は、Arrow を経由せず直接 DataFrame が返るため、この区間分けはできません。
5.2. 実施状況
全件スケールでは query_arrow の 1 ラウンドがメモリ割り当てエラーで失敗し、そのラウンドを除いた 4 ラウンドで集計しています。JSONEachRow は 1,000万行のスケールで pandas への読み込み中にメモリ不足(MemoryError)が発生しました。空きメモリの量を変えて 2 回試しても同じ結果になったため、一時的なものではなく、この方法が 1,000万行規模で実行できなくなることを示しています。全件(4,327万行)ではさらに悪化するのが明らかなため、JSONEachRow は 100万行のスケールのみ実施しました。
JSONEachRow は ClickHouse の HTTP インターフェースに FORMAT JSONEachRow を付けて実行し、返ってきた JSON テキストを pandas.read_json で読み込む方法です。100万行では問題なく実行できますが、1,000万行では 1 行ずつ JSON をパースする際のメモリ使用量がふくらみ、実行そのものができなくなりました。
これらの例外を除く全ラウンドで、取得した行数と cell 列の合計値(チェックサム代わり)が 5 つの方法すべてで一致することを確認しています。
5.3. 相対比較
query_df を 1.00 とした、DataFrame(pandas)到達までの相対時間です。
| 方法 | 100万行 | 1,000万行 | 全件(4,327万行) |
|---|---|---|---|
query_df |
1.00 | 1.00 | 1.00 |
query_arrow |
0.87 | 0.49 | 0.69(4 ラウンドの中央値) |
query_df_arrow |
0.71 | 0.47 | 0.66 |
| ADBC | 0.40 | 0.26 | 0.22 |
| JSONEachRow | 9.73 | 未実施 | 未実施 |
行数が増えるほど ADBC の優位が広がっています。全件では query_df の約 4.5 倍速く、次点の query_df_arrow(約 1.5 倍速い)とも差が開いています。
Arrow を経由する query_arrow と ADBC は、pandas だけでなく polars への到達時間も測っています。
| 方法 | 100万行 | 1,000万行 | 全件 |
|---|---|---|---|
query_arrow |
0.35 | 0.44 | 0.65(4 ラウンドの中央値) |
| ADBC | 0.40 | 0.27 | 0.29 |
100万行では query_arrow の方が polars への到達がわずかに速く、1,000万行から ADBC が上回ります。この逆転がどこで起きているかは、5.4 章でもう一段掘り下げます。
5.4. 差はどこで生まれているか
Arrow テーブルが届くまでの時間だけを取り出すと、実は 100万行では ADBC の方がわずかに遅く、1,000万行から逆転しています。
| 方法 | 100万行 | 1,000万行 | 全件 |
|---|---|---|---|
query_arrow |
0.48 秒 | 3.72 秒 | 25.65 秒(4 ラウンドの中央値) |
| ADBC | 0.57 秒 | 2.24 秒 | 8.48 秒 |
サーバー側の system.query_log を同じクエリで突き合わせると、この差はほぼサーバー側の処理時間で説明できます。全件スケールでの実行時間の中央値は query_arrow が 23,150 ミリ秒、ADBC が 8,002 ミリ秒で、送信バイト数はどちらも約 11.3 億バイトとほぼ同じでした。転送量が同じなのに処理時間が約 2.9 倍違うということは、差はネットワークではなくサーバーが Arrow 形式を作る処理そのものにあります。
スケールごとの比率を見ると、この差は行数が増えるほど広がっています。100万行・1,000万行では query_arrow がおよそ 1.7 倍遅い程度でしたが、全件では約 2.9 倍まで広がりました。ADBC 側の処理時間は 1,000万行から全件(4.3 倍の行数)でほぼ 4.3 倍に増えており、行数に比例しています。一方 query_arrow は同じ行数の増え方に対して約 7.4 倍に増えており、比例よりも大きく伸びていました。
6. 考察
6.1. Arrow 形式と ArrowStream 形式の違い
5.4 章で見たとおり、query_arrow と ADBC のサーバー側処理時間の差は行数が増えるほど広がり、ADBC が使う形式はほぼ行数に比例してスケールしていました。
ClickHouse の公式ドキュメントは、この 2 つの形式を書き分けています。Arrow は Apache Arrow の「ファイルモード」形式で、インメモリのランダムアクセス向けに設計されています6。対して ArrowStream はレコードバッチの並びとして配信され、受信側は届いたバッチから順に読み進められます8。
この設計の違いが、今回測った処理時間の伸び方の違いに対応していると考えられます。query_arrow が使う Arrow 形式は結果全体をまとめて書き出す必要があるため、行数が増えるほど処理時間が比例以上に伸びる一方、ADBC が使う ArrowStream はバッチ単位で逐次書き出せるため、行数に比例した処理時間で済んでいるものと考えられます。ClickHouse サーバー内部の実装まで確認できたわけではないため、あくまで公式ドキュメントの記述と実測の傾向が一致する、という範囲の説明です。
6.2. 既存クライアントでも ArrowStream は使える
では、この形式は ADBC でないと使えないのでしょうか。調べ直すと、clickhouse-connect には query_arrow とは別に query_arrow_stream というメソッドがあり、レコードバッチを順に受け取れます。ドキュメントの Advanced Querying ページには説明が記載されていませんが(1.5.0 時点)、実行して system.query_log を確認すると、クエリ本文に FORMAT ArrowStream が付与されていました。ADBC と同じ形式を、既存クライアントからも要求できるということです。
この 3 つ(query_arrow / ADBC / query_arrow_stream)だけを同条件で測り直した結果が次の表です。Arrow テーブル到達までの中央値(秒)で、query_arrow_stream は受け取ったバッチをすべて読み切って 1 つの pyarrow.Table に結合し終えた時点を到達とみなしています。
| 方法 | 100万行 | 1,000万行 | 全件(4,327万行) |
|---|---|---|---|
query_arrow |
0.34 秒 | 3.12 秒 | 24.50 秒 |
| ADBC | 0.52 秒 | 2.14 秒 | 11.96 秒 |
query_arrow_stream |
0.23 秒 | 2.10 秒 | 11.56 秒 |
query_arrow_stream は全スケールで ADBC と同水準(全件では query_arrow の半分以下)でした。5 章の計測とは別の時間帯に実施したため絶対値は 5 章の表と直接比較できませんが、この表の 3 方法は同一ラウンド内で交互に実行しており、3 方法の間の比較はそのまま成り立ちます。速さの差が ADBC という実装ではなく ArrowStream という形式に由来することを、既存クライアント単体でも確かめられました。
なお query_arrow_stream は、受け取ったバッチを 1 つずつ処理していく使い方もできます。その場合は全件を 1 つの pyarrow.Table に保持せずに済みます(今回の計測は他の方法と条件を揃えるため、全バッチを結合しています)。
6.3. Arrow から pandas への変換速度の違い
全件スケールで、Arrow テーブルが届いたあと pandas に変換するまでの時間は、query_arrow が約 3.2 秒だったのに対し ADBC は約 0.8 秒でした。同じ規模で追加検証として、届いた pyarrow.Table のスキーマ・チャンク数・チャンクごとのバイト数を両者で直接比較しましたが、すべて完全に一致していました(100万行・全件のどちらでも一致)。
スキーマやチャンク構成という、Python から確認できる範囲では差がないため、原因は clickhouse-connect(Arrow 形式を Python 側で解析する実装)と ADBC(Rust 製ドライバが Arrow の C Data Interface 経由で直接引き渡す実装)の、メモリの持ち方やコピーの回数といった、より低いレイヤーの違いにあると考えられます。ここは pyarrow の公開 API からは確認できず、仮説にとどまります。
6.4. 圧縮の効果とリモート環境での再現性
3.2 章で見たとおり、ADBC は常に ClickHouse 独自の圧縮を有効にして送っていますが、ローカルの実測ではこの圧縮による送信バイト数の減少はほとんど見られませんでした(0.2〜0.4% 程度)。
当初は「帯域が制約になるリモート環境では、圧縮の有無が結果を変えるのではないか」と考えていたため、同じベンチを ClickHouse Cloud(AWS ap-northeast-1 の小型サービス、バージョン 26.2.1.525)相手にインターネット経由でも実施しました。圧縮の影響だけを取り出すため、query_arrow は圧縮なし・圧縮あり(compress=True)の両方を測っています。query_arrow の圧縮なしを 1.00 とした、Arrow テーブル到達の相対時間です。
| 方法 | 100万行 | 1,000万行 | 全件(4,327万行) |
|---|---|---|---|
query_arrow(圧縮なし) |
1.00(0.71 秒) | 1.00(4.09 秒) | 1.00(20.75 秒) |
query_arrow(圧縮あり) |
1.03 | 1.01 | 1.00 |
query_arrow_stream |
0.83 | 0.62 | 0.49 |
| ADBC | 0.92 | 0.66 | 0.49 |
圧縮あり・なしの差は、送信バイト数がどのスケールでも 1 バイト、所要時間で 0.4〜2.5% と誤差の範囲でした。「リモートでは圧縮が結果を変える」という当初の想定は、実測では外れました。cell_towers は緯度経度など Float64 が主体で、圧縮でほとんど縮まないデータだったためです。
一方、ArrowStream の優位はリモートでも残り、行数が増えるほど広がりました(query_arrow 比で 100万行 17%、全件 51% 速い)。ローカルで見えた「サーバー側の出力形式が支配的」という構図は、今回のリモート条件でも同じでした。
圧縮の効果を左右するのは「ローカルかリモートか」ではなく「データが圧縮で縮むかどうか」だと考えられます。文字列主体で圧縮が縮みやすいデータや、今回より帯域の細い回線では、圧縮の有無が転送時間を左右する可能性はあります。
6.5. ADBC の価値はどこにあるのか
ここまでの実測では、ADBC が速い理由は「ArrowStream という、より効率のよいサーバー側の出力形式を使っている」ことに帰着します。そして 6.2 章のとおり、同じ形式は clickhouse-connect の query_arrow_stream からも使え、速さも同水準でした。つまり Python に限れば、速さのために ADBC を選ぶ必要はありません。
その意味で ADBC の価値は、公式ブログが掲げる「1 つのドライバ・1 つの形式で言語を横断する」という標準化にあると捉えるのが妥当です1。Arrow ADBC の API は他の言語・他のデータベースでも共通で、公式クライアントのない言語からも同じ書き方で接続できます。今回の実測は、その標準 API が速さの面でも既存クライアントの最速手段と同水準にある、という確認になりました。
この標準化は ClickHouse 専用の話ではありません。たとえば DuckDB は公式の ADBC ドライバを提供しており、Arrow とのゼロコピー統合でデータを受け渡します9。同じ接続コードのまま接続先を ClickHouse から DuckDB や PostgreSQL に差し替えたり、ClickHouse から Arrow で受け取った結果を DuckDB や polars でそのまま加工し続けたり、といった組み合わせが行形式への変換なしにつながります。今回測った「Arrow のまま届く」経路は、この Arrow 前提のエコシステムへの入り口という位置づけです。
7. まとめ
| 観点 | 結論 |
|---|---|
速さ(query_df 比) |
ADBC が最速で全件約 4.5 倍。追加実測では query_arrow_stream も同水準 |
| 差の理由 | サーバー側の出力形式。Arrow は行数の増加より速いペースで処理時間が伸び、ArrowStream はほぼ比例 |
| pandas 変換速度 | ADBC の方が速いが、Arrow テーブルの構造では説明できず、パーサ実装の違いという仮説どまり |
| 型の対応 | 25 型中 JSON のみ失敗。ADBC 固有ではなくサーバー側の制約 |
| JSONEachRow 経路 | 1,000万行でメモリ不足により実行不能 |
| 圧縮 | ローカル・リモートとも今回のデータでは差がほぼ出ない(圧縮の縮みやすさに依存) |
| リモート再現性 | ClickHouse Cloud 相手でも ArrowStream 優位は残り、規模とともに拡大 |
大量データを Python に運ぶことだけが目的なら、clickhouse-connect の query_arrow を query_arrow_stream へ切り替えるのが最短です。速さは ADBC というドライバそのものではなく、それが使っているサーバー側の出力形式で、同じ形式は既存クライアントからも使えます。そのうえで、複数の言語やデータベースを同じ API で扱いたい場合に、ADBC を選ぶ理由が出てきます。
速さだけで選ぶと 4 章の型の境界の考慮が必要になります。Enum8 のラベルや IPv4 / IPv6 のアドレス表現をそのまま扱いたいなら、Arrow を経由しない query_df の方が手間は少なくなります。逆に大量の数値主体のデータを扱う場面で、多少の型変換を実施しても良い前提なら、query_arrow_stream ・query_df_arrow ・ADBC のような Arrow 経由の方法を選ぶ理由が今回の実測で裏付けられました。
参考
-
One Driver, One Format, Every Language: ADBC(ClickHouse 公式ブログ、2026年7月10日)。設計思想と "When to use a language client instead" 節(型マッピングの限界・async 非対応・ORM 用途への言及) ↩ ↩2 ↩3 ↩4
-
ClickHouse/adbc_clickhouse README。バージョン 0.1.0-alpha.1、接続オプション(
Uri/Username/Password)、IngestMode は Append のみ ↩ ↩2 -
clickhouse-connect: Advanced Querying。"PyArrow queries" 節(
query_arrowは ClickHouse のArrow形式を直接使う)、"Arrow-backed DataFrames" 節(query_df_arrowはゼロコピーに近い変換) ↩ -
cell_towers データセット。DDL とロード手順 ↩
-
ClickHouse HTTP Interface。
compress=1パラメータが ClickHouse 独自の圧縮形式を使う旨の記載(標準のAccept-Encoding圧縮とは別) ↩ -
ClickHouse Docs: Arrow format。Apache Arrow の「ファイルモード」形式で、インメモリのランダムアクセス向けに設計されている旨の記載 ↩ ↩2
-
同上ブログのロードマップ節。JSON 対応は Arrow 側の標準的なシリアライズ形式の確定待ちと記載 ↩
-
ClickHouse Docs: ArrowStream format。レコードバッチの並びとして逐次読み進められる旨の記載 ↩
-
DuckDB Docs: ADBC Client。DuckDB が ADBC ドライバを提供し、DuckDB と Arrow のゼロコピー統合でデータを転送する旨の記載 ↩