🦆

ブラウザSQLクエリ実行も可能なDuckDBざっくりまとめ

2024/12/03に公開

(アプリボットアドベントカレンダー)[https://qiita.com/advent-calendar/2024/applibot] 3日目です。

今所属しているプロジェクトの展望として、webのダッシュボードを構築する可能性が出てきました。
最初に必要なデータを取得し、その後はWebフロントエンドだけで部分的にクエリ実行やデータ出し分けができれば、通信を行わず効率的に操作できて便利だと感じました。
調べたところ、DuckDBというものがあり、面白そうだったので軽く調べてみました。

DuckDBは軽量でありながら強力な分析機能を持つデータベースです。
高速で扱いやすいOLAP(オンライン分析処理)向けのデータベース「DuckDB」の概要と便利SQLを軽くまとめました。

背景

SQLiteはInstallが容易でアプリケーション内のプロセスに組み込まれて動作するデータベースエンジンです。
SQLiteのような行指向データベース(例えばPostgreSQLやMySQLなども)は、トランザクション処理に優れています。ただ、一方で大量のデータに対する集計や分析処理におけるユースケースでは、列指向データベースが有利とのこと。SQLiteのような指向(Installが容易かつプロセス内組み込み動作..)かつ分析処理ワークロードが得意なデータベースがなかったことからDuckDBの開発に至ったようです。

DuckDBの概要と分析に適する理由

DuckDBは、データ分析に特化した列指向データベースであり、メモリ内での高速処理が可能です。これにより、重たい分析クエリでも軽快に実行できるというメリットがあります。また、SQLiteの特徴でもある他のデータベースと比べてセットアップが簡単で、プロセスに組み込まれて動作する点が特徴です。

特徴 SQLite DuckDB
ストレージ方式 行指向 列指向
実行エンジン 行ごとの逐次処理 ベクトル化実行による並列処理
得意な処理 OLTP (トランザクション処理) OLAP (分析処理)
外部データソース 主にローカルファイル Parquet, CSV, PostgreSQL, S3等多様

先述の通り、DuckDBはSQLiteの分析版として提起されています。
https://mytherin.github.io/papers/2019-duckdbdemo.pdf

SQLiteは行指向で各レコード(行)ごとにデータを格納し、トランザクションの処理に強みがある一方で、DuckDBは列指向で列ごとにデータを格納します。列要素でまとめているため型が同じで圧縮効率も高く、同じカラムに対する集計処理やフィルタを行うことが得意です。

移植性

  • os
    • Linux、macOS、Windows
  • CPUアーキテクチャ
    • x86、ARM
  • DuckDB-wasmによりブラウザは携帯電話でも実行可能

豊富な言語Binding

  • Java、C、C++、Go、Node.jsなど

高速

OLAP/OLTPの対称比較は以下

条件 OLAP OLTP
目的 大量のデータを分析して意思決定を支援するのに役立つ リアルタイムトランザクションの管理と処理に役立つ
データソース 複数のソースからの履歴データおよび集計データを使用 単一ソースからのリアルタイムデータとトランザクションデータを使用
データ構造 多次元 (キューブ) データベースまたはリレーショナルデータベースを使用 リレーショナルデータベースを使用
データモデル スタースキーマ、スノーフレークスキーマ、またはその他の分析モデルを使用 正規化モデルまたは非正規化モデルを使用
データ量 大量のストレージ要件があり、テラバイト (TB) またはペタバイト (PB) レベル 比較的小さなストレージ要件があり、ギガバイト (GB) レベル
応答時間 長く、通常は秒単位または分単位 短く、通常はミリ秒単位
アプリケーション例 傾向の分析、顧客行動の予測、収益性の特定に適している 支払い処理、顧客データ管理、注文処理に適している

https://aws.amazon.com/jp/compare/the-difference-between-olap-and-oltp/

DuckDBで使える便利なSQLまとめ

DuckDBを使う上で知っておくと便利なSQL機能をざっくり紹介です。

live demoは以下
https://shell.duckdb.org/

File Import機能

DuckDBの強みの一つが複数のファイル形式をインポートしてクエリを実行して分析できることです。
CSV、JSON、Parquetといった形式がインポート可能です。

例えば、CSVファイルをインポートする場合、以下のようなクエリを使います。

SELECT * FROM 'flights.csv';

read_csv関数で個別オプションを付与することもできます。

SELECT *
FROM read_csv('flights.csv',
    delim = '|',
    header = true,
    columns = {
        'FlightDate': 'DATE',
        'UniqueCarrier': 'VARCHAR',
        'OriginCityName': 'VARCHAR',
        'DestCityName': 'VARCHAR'
    });

https://duckdb.org/docs/data/csv/overview

複数ファイルのJoinクエリ

DuckDBでは複数のファイルを対象にしたJOINも容易に行えます。例えば、2つの異なるCSVファイルを結合する際、以下のようにクエリを実行できます。

SELECT *
FROM read_csv_auto('path/to/data1.csv') AS t1
JOIN read_csv_auto('path/to/data2.csv') AS t2
ON t1.id = t2.id;

異なるファイルからのデータを手軽にJOINすることで、このようにデータソースの形式が違ったとしてもデータの関連付けが簡単に行えます。

Asof Join

テーブル (価格など) で最も時間が近い (最初の)データを見つけて結合するのに便利なASOF JOIN

## https://duckdb.org/docs/sql/query_syntax/from#as-of-joins
SELECT t.*, p.price
FROM trades t
ASOF JOIN prices p
       ON t.symbol = p.symbol AND t.when >= p.when;

集約関数

集計処理に便利な集約関数。DuckDBは標準的な集約関数(SUM、AVG、COUNTなど)を提供されてます。

SELECT product, SUM(sales) AS total_sales
FROM sales_data
GROUP BY product;

lambda関数もかける、便利!

SELECT list_transform(
        list_filter([0, 1, 2, 3, 4, 5], x -> x % 2 = 0),
        y -> y * y
    );

Exclude

特定のカラムを除外するEXCLUDEが使える。

SELECT * EXCLUDE (column_to_exclude)
FROM sales_data;

bigqueryのexceptとかsnowflakeのexcludeと同じ(bigqueryにあるの知らなかった)

Replace As

式で指定したカラムの特定の値を置き換えることができます。
便利!

SELECT * REPLACE (col * 1000 AS col) FROM tbl;

まとめ

DuckDBは、列指向の仕組みにより高速な分析クエリが実行可能で、データインポートやファイル間の結合など、豊富な機能を持つ便利で手軽なデータベースです。また、DuckDB-wasmを使えばブラウザ実行できるなど、効率的なデータ分析を進めることができます。データの可視化や分析ダッシュボード構築、機会あればがんばります!

Discussion