HN 日本語サマリー

← 一覧へ戻る
プログラミング

DuckDB 2.0 が高速化された理由

Why DuckDB 2.0 is faster (motherduck.com)

64 pointsby tosh17 コメント

要約

DuckDB 2.0 では、非同期 I/O の導入により S3 からデータの読み込み速度が 2~3 倍向上しました。これは、バックグラウンドでデータをダウンロードする専用のスレッドプールが追加されたためです。また、再帰的 CTE のエンジンが書き直され、グラフ探索のようなディープな親子関係を持つデータセットの処理が大幅に高速化されました。

全文翻訳

GO BACK TO BLOG Why DuckDB 2.0 is faster 2026/09/10 - 15 min read BY Mehdi Ouazza DuckDB 2.0 がこの秋にリリースされ、アルファ版が公開されました!データベースエンジンを構築するのではなく、テーブルやパイプラインを構築する人々にとって実際に何が変わるのかを知るために、興味深い機能を自分のラップトップ上で、そして S3 に対して実行してみました。なぜなら、DuckDB 2.0 は確かに高速化されているからです。しかし、その速度向上を得るためには、データの形状を理解し、時にはそれをどのようにモデリングするかを理解する必要があります。この記事では、私が最も重要だと考える 3 つの機能と、私が得た数値、そしてコミットログで見つけたいくつかの隠れた宝石について説明します。以下のすべての数値は、1 台のマシン(M5 ラップトップ)と私の自宅のインターネット回線から得られたもので、どちらのバージョンもほぼ同じように遅くなります。引用する前に、ご自身で実行してみてください ;) 最も簡単でエキサイティングなものから始めましょう:非同期 I/O。 非同期 I/O: AWS S3 越しのクエリが大幅に高速化 これは私が最も気に入っている機能です。なぜなら、クエリの何も変わらないからです。以下は、S3 上の 2.2 GB の Parquet ファイル(Stack Overflow の投票データ、2億2800万行、2268 の行グループ)を読み込み、タイプごとの投票数をカウントするクエリです。4 つの列のうち 1 つ、約 230 MB を読み込みます。 CREATE SECRET s3 (TYPE s3, PROVIDER credential_chain, REGION 'us-east-1'); SET enable_external_file_cache = false; -- so every run really hits S3 SELECT VoteTypeId, count(*) AS n FROM read_parquet('s3://us-prd-motherduck-open-datasets/stackoverflow/parquet/2023-05/votes.parquet') GROUP BY ALL ORDER BY 1; 同じクエリ、同じラップトップ DuckDB 1.5.5 18.8 s DuckDB 2.0 alpha 7.7 s 簡単な注意点:導入で述べたように、これは私の自宅のインターネット回線から us-east-1 への接続なので、両方の数値は遅いです。クラウドコンピューティングから実行する場合は、もっと速くなるはずです。 では、この魔法は何でしょうか? ファイルは、約 122,000 行の 2268 の行グループに分割されています。行グループごとに、DuckDB はバイトをダウンロードし、Parquet をデコードし、タイプごとの投票数をカウントし、最後に部分的なカウントをマージします。2 種類の作業があります:ネットワークの待機と CPU の処理です。 1.5.5 では、18 のワーカーそれぞれが、ダウンロード、待機、デコード、ダウンロード、待機というように、両方のジョブを順番に実行します。ワーカーが待機中は CPU はアイドル状態になり、デコード中はダウンロードが進行せず、一度に 18 件以上のダウンロードが行われることはありません。 2.0 では、スレッドの別個のプールがダウンロードのみを行い、数十の行グループをインフライト状態に保ち、バイトをバッファに格納します。ワーカーはデコードのみを行い、常にデコード準備のできた行グループがあります。ネットワークと CPU は同時にビジー状態になります。 非同期 I/O SELECT VoteTypeId, count(*) AS n FROM read_parquet('s3://…/votes.parquet') GROUP BY ALL ORDER BY 1; DuckDB 1.5.5 download, wait, decode, repeat votes.parquet · 2268 row groups · one column 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 worker 1 idle wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode done worker 2 idle wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode done worker 3 idle wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode done worker 4 idle wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode wait decode done elapsed 0.0 s 0.2 s 0.4 s 0.6 s 0.8 s 1.0 s 1.2 s 1.4 s 1.6 s 1.8 s 2.0 s 2.2 s 2.4 s 2.6 s 2.8 s 3.0 s 3.2 s 3.4 s 3.6 s 3.8 s 4.0 s 4.2 s 4.4 s 4.6 s 4.8 s 5.0 s 5.2 s 5.4 s 5.6 s 5.8 s 6.0 s 6.2 s 6.4 s 6.6 s 6.8 s 7.0 s 7.2 s 7.4 s 7.6 s 7.8 s 8.0 s 8.2 s 8.4 s 8.6 s 8.8 s 9.0 s 9.2 s 9.4 s 9.6 s 9.8 s 10.0 s 10.2 s 10.4 s 10.6 s 10.8 s 11.0 s 11.2 s 11.4 s 11.6 s 11.8 s 12.0 s 12.2 s 12.4 s 12.6 s 12.8 s 13.0 s 13.2 s 13.4 s 13.6 s 13.8 s 14.0 s 14.2 s 14.4 s 14.6 s 14.8 s 15.0 s 15.2 s 15.4 s 15.6 s 15.8 s 16.0 s 16.2 s 16.4 s 16.6 s 16.8 s 17.0 s 17.2 s 17.4 s 17.6 s 17.8 s 18.0 s 18.2 s 18.4 s 18.6 s 18.8 s DuckDB 2.0 alpha a pool downloads ahead, workers only decode votes.parquet · 2268 row groups · one column 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 dl pool idle fetch done worker 1 idle decode done worker 2 idle decode done worker 3 idle decode done elapsed 0.0 s 0.2 s 0.4 s 0.6 s 0.8 s 1.0 s 1.2 s 1.4 s 1.6 s 1.8 s 2.0 s 2.2 s 2.4 s 2.6 s 2.8 s 3.0 s 3.2 s 3.4 s 3.6 s 3.8 s 4.0 s 4.2 s 4.4 s 4.6 s 4.8 s 5.0 s 5.2 s 5.4 s 5.6 s 5.8 s 6.0 s 6.2 s 6.4 s 6.6 s 6.8 s 7.0 s 7.2 s 7.4 s 7.6 s 7.7 s これを駆動する 1 つの設定は、read_ahead_depth です。これは、ダウンロードプールがワーカーの先行してフェッチできる行グループの数です。デフォルトは -1(自動、スレッド数からサイズ決定)なので、非同期 I/O はデフォルトでオンになっています。これを 0 に設定すると、1.5 の動作に戻ります。 S3 読み込み 1.5.5 2.0 alpha 1 つの 2.2 GB Parquet ファイル、1 列 18.8 s 7.7 s 23 個の大きな Parquet ファイル、13.6 GB、1 列 11.8 s 3.9 s 1 つの 1.7 GB のプレーン CSV 116 s 55 s 30 個の小さな Parquet ファイル、それぞれ約 1 MB 3.7 s 3.3 s 小さなファイルに関するコメント:意味のある変化はありません。なぜなら、そこでの時間はファイルごとの往復(フッター、次にデータ)であり、先行読み込みでは削除できないからです。1 MB のファイルが数千個あるデータレイクを格納するのは、 anyway 悪いプラクティスであり、2.0 はそれを救いません。基本は依然として重要です! TL;DR: S3 越しのデータ読み込みは、クエリの変更なしで 2.0 では 2~3 倍高速です。これは、ワーカーの先行してダウンロードする別個のプールがあるためです。デフォルトでオンになっています(read_ahead_depth = -1)。0 にすると古い動作になります。 再帰的 CTE: ディープな親子データセットのブースト DuckDB チームは再帰的 CTE エンジンを書き直し、グラフ到達可能性で 40 倍の性能向上を主張しています。心配しないでください、あなたがすでに知っているテーブルでそれが何を意味するのか説明します。 再帰的 CTE は、テーブルに対するループです。2 つの列、マネージャーと従業員を持つ従業員テーブルを考えます。あなたは簡単な質問に答えたいのです:誰が誰に報告しているか。 manager employee Ana Ben Ana Cléa Ben Dev Ben Eli Cléa Fay Dev Gus Fay Hal それを実行するには、1 行から始めます:CEO の Ana です。ラウンド 1 では、Ana のマネージャーである全員(Ben, Cléa)を見つけます。ラウンド 2 では、それらの人のいずれかをマネージャーとする全員(Dev, Eli, Fay)を見つけます。ラウンドで見つからなくなるまで続けます。組織図の各レベルが 1 ラウンドです。 クエリは次のようになります。 WITH RECURSIVE team(person) AS ( SELECT 'Ana' UNION SELECT e.employee FROM team t JOIN employees e ON e.manager = t.person ) SELECT count(*) FROM team; 組織図、フォルダツリー、部品表、返信スレッド、データリネージ、git の履歴:これらはすべて、テーブルがしばしば同じ 2 つの列、親と子であるようなデータの種類です。唯一の違いは、それがどれだけ深く進むかであり、深さはクエリのラウンド数です。組織図はせいぜい 8 レベルです。git の履歴は数万レベルです。 1.5 が抱えていた問題はこれです。各ラウンドで、次のレベルを見つけるためにテーブル全体を再読み込みしていました。8 レベルということは 8 回のフルリードを意味します。数千レベルということは、同じテーブルの数千回のフルリードを意味します。2.0 では、テーブルは 1 回だけ読み込まれ、親列に対するルックアップが 1 回構築され、各ラウンドでは見つかった少数の行だけが検索されます。コストは、テーブルサイズにラウンド数を掛けたものではなく、実際にタッチした行数になりました。 再帰的 CTE WITH RECURSIVE team(person) AS ( SELECT 'Ana' UNION SELECT e.employee FROM team t JOIN employees e ON e.manager = t.person ) SELECT count(*) FROM team; DuckDB 1.5.5 各ラウンドでテーブルを再読み込み manager employee Ana Ben Ana Cléa Ben Dev Ben Eli Cléa Fay Dev Gus Fay Hal Fay Ida Gus Jon Hal Kim frontier Ana Ben, Cléa Dev, Eli, Fay Gus, Hal, Ida rows read round 1 · 10 round 2 · 10 round 3 · 10 round 4 · 10 rows read 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 DuckDB 2.0 alpha 1 回読み込み、各ラウンドでルックアップ manager employee Ana Ben Ana Cléa Ben Dev Ben Eli Cléa Fay Dev Gus Fay Hal Fay Ida Gus Jon Hal Kim frontier Ana Ben, Cléa Dev, Eli, Fay Gus, Hal, Ida manager lookup Ana → Ben, Cléa Ben → Dev, Eli Cléa → Fay Dev → Gus Fay → Hal, Ida Gus → Jon Hal → Kim rows touched 0 1 2 3 4 5 6 7 8 9 10 Coming back to g