Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PG-StromのParquetを爆速化する“Parquet NVME Cache”

PG-StromのParquetを爆速化する“Parquet NVME Cache”

PG-Strom v6.2の新機能 "Parquet NVME Cache" についての解説です。

PG-Stromに詳しい方は p.39 以降をご覧ください。

Avatar for KaiGai Kohei

KaiGai Kohei

June 01, 2026

More Decks by KaiGai Kohei

Other Decks in Technology

Transcript

  1. 自己紹介/HeteroDB社について 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 2 会社概要  商号

    ヘテロDB株式会社  創業 2017年7月4日  拠点 東京都品川区北品川  事業内容 高速データベース製品の販売 GPU&DB領域の技術コンサルティング ヘテロジニアスコンピューティング技術を データベース領域に適用し、 誰もが使いやすく、安価で高速なデータ解析基盤を提供する。 代表者プロフィール  海外 浩平(KaiGai Kohei)  OSS開発者コミュニティにおいて、PostgreSQLやLinux kernelの 開発に10年以上従事。主にセキュリティ・FDW等の分野でアッ プストリームへの貢献。  IPA未踏ソフト事業において“天才プログラマー”認定 (2006)  GPU Technology Conference Japan 2017でInception Awardを受賞
  2. 製品概要 PG-Stromとは? 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 4 【機能】 

    集計/解析ワークロードの透過的なGPU高速化  SQLからGPUプログラムを自動生成し超並列実行  GPU-Direct SQLによるPCIeバスレベルのI/O最適化を行う  Apache Arrow / Parquetに対応し、M2Mログデータの処理にフォーカス ➔ これらの力を最大限に引き出すParquet NVME Cache(本日のテーマ) PG-Strom: GPUとNVMEの能力を最大限に引き出し、 テラバイト級のデータを高速処理するPostgreSQL向け拡張モジュール App GPU off-loading ➢ GpuScan / GpuJoin / GpuPreAgg ➢ GPU-Direct SQL ➢ Apache Arrow / Parquet support (with min/max statistics) ➢ Parquet NVME Cache ➢ Asymmetric Partition-wise JOIN/GROUP BY ➢ Large Tables GPU-JOINs ➢ BRIN-Index support ➢ pg2Arrow / mysql2arrow / pcap2arrow
  3. PostgreSQLにGPUを試そうとしたきっかけ ▌PGconf 2011 (Ottawa) で聴講したあるセッション・・・  Parallel Image Searching Using

    PostgreSQL and PgOpenCL Running PostgreSQL Stored Procedures on a GPU ✓ https://www.pgcon.org/2011/schedule/events/352.en.html  画像処理用のストアドプロシジャを、GPU用のプログラミング環境 OpenCL で作成するための拡張モジュールについて。 A列 B列 C列 D列 E列 幅の小さいデータでも、 大量の行を並べれば 長大なBLOBと同じく GPU並列処理が効くのでは? 2011 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 5
  4. GPU(Graphics Processing Unit)とはどんなプロセッサなのか? 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 6 元々は3Dゲームでポリゴンの座標を高速に計算するためのデバイス

    ➔ 汎用計算にも安く使えるという事で、HPCや機械学習の分野でも スーパーコンピュータ (東京工業大学 TSUBAME3.0) CG(Computer Graphics) 機械学習 数百~数千コアの並列処理ユニットと、TB/sを越える帯域のメモリを搭載。 大量の計算処理を得意とするが、専用のS/Wやアルゴリズムが必要。 CUDA Toolkitによって容易にSW開発が可能となった。 シミュレーション NVIDIA H100 RTX 4090Ti 3D Gaming
  5. CPUとGPUの設計思想の違い(1/3) GPU DRAM DRAM Cache Cache ✓ データアクセスの局所性 ✓ キャッシュ&高クロック

    ➔ 処理のレイテンシに優位性 ✓ 次から次へと、データを演算器に 流し込む事に特化した構造。 ✓ 広帯域メモリ&大容量レジスタ ➔ 処理のスループットに優位性 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 7 小回りが利くが輸送力は 小さな乗用車のような プロセッサ 使える状況が限られるが、 大量輸送が可能な 高速鉄道のような プロセッサ
  6. CPUとGPUの設計思想の違い(2/3) LZ77圧縮アルゴリズムの例 (F,8,’capybara’) (T,4,4) ’c’ ’a’ ’p’ ’y’ ’b’ ’a’

    ’r’ ’a’ (T,4,3) (T,14,3) ’c’ ’a’ ’p’ ’y’ ’b’ ’a’ ’r’ ’a’ ’b’ ’a’ ’r’ ’a’ ’c’ ’a’ ’p’ ’y’ ’b’ ’a’ ’r’ ’a’ ’b’ ’a’ ’r’ ’a’ ’b’ ’a’ ’r’ ’c’ ’a’ ’p’ ’y’ ’b’ ’a’ ’r’ ’a’ ’b’ ’a’ ’r’ ’a’ ’b’ ’a’ ’r’ ’a’ ’p’ ’y’ 4文字戻って4文字を追記 4文字戻って3文字を追記 14文字戻って3文字を追記 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 8
  7. CPUとGPUの設計思想の違い(3/3) 行列積の計算の例 x0 x1 x2 x3 x4 x5 x6 x7

    xk xn × × × × × × × × × × y0 y1 y2 y3 y4 y5 y6 y7 yk yn + + + + + + + + 計算の依存性無し 計算の依存性は最小限 隣の要素の計算が 終わっていれば、 加算を実行可能 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 9
  8. コレって検索ワークロードに似ていない? テーブルスキャンの方向 x_val = 123 x_val = 234 x_val =

    345 x_val = 456 x_val = 567 WHERE x_val % 2 = 1 〇 × 〇 × 〇 • • • • • GPUコア ✓ DBテーブルをある種のベクトルと見なせば、 一度の処理サイクルで数千~万行の処理が可能に 行列計算の場合 テーブルスキャンの場合 𝑣 × 𝐴 v0 v1 v2 v3 vn-4 vn-3 vn-2 vn-1 ak,0 ak,1 ak,2 ak,3 ak,n-4 ak,n-3 ak,n-2 ak,n-1 × × × × × × × × ベクトル v 行列A 異なるデータに 同じ演算を多数実行 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 10
  9. Custom-Scan APIs(1/5) 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 12 PostgreSQLのテーブルを Scan/Join

    する代替の方法を定義する 2014 SQLパーサ オプティマイザ エグゼキュータ クエリ木 (内部形式) 実行計画 SQL構文 問い合わせ結果 buffer manager transaction control metadata cache IPC & Lock index access transaction logs 拡張モジュール • 実行計画を作成・登録 • 実行開始 • 次の1行を返す • 実行終了 set_rel_pathlist_hook set_join_pathlist_hook create_upper_paths_hook それぞれPostgreSQLのテーブルを Scan/Join/Group-byするタイミングで 呼び出されるフックを追加 ExecCustomScan() どう実装するかは 拡張モジュールが 任意に決める事が できる。
  10. Custom-Scan APIs(2/5) 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 13 ssbm=# explain

    select sum(lo_revenue), d_year, p_brand1 from lineorder, date1, part, supplier where lo_orderdate = d_datekey and lo_partkey = p_partkey and lo_suppkey = s_suppkey and p_category = 'MFGR#12’ and s_region = 'AMERICA’ group by d_year, p_brand1; QUERY PLAN --------------------------------------------------------------------------------------------------- HashAggregate (cost=192049053.77..192049141.27 rows=7000 width=46) Group Key: date1.d_year, part.p_brand1 -> Hash Join (cost=373962.46..191695451.95 rows=47146910 width=20) Hash Cond: (lineorder.lo_orderdate = date1.d_datekey) -> Hash Join (cost=373857.95..191571381.58 rows=47146910 width=20) Hash Cond: (lineorder.lo_suppkey = supplier.s_suppkey) -> Hash Join (cost=55265.84..190631708.88 rows=236602030 width=26) Hash Cond: (lineorder.lo_partkey = part.p_partkey) -> Seq Scan on lineorder (cost=0.00..174826341.12 rows=6000026112 width=20) -> Hash (cost=54280.00..54280.00 rows=78867 width=14) -> Seq Scan on part (cost=0.00..54280.00 rows=78867 width=14) Filter: (p_category = 'MFGR#12'::bpchar) -> Hash (cost=293684.47..293684.47 rows=1992611 width=6) -> Seq Scan on supplier (cost=0.00..293684.47 rows=1992611 width=6) Filter: (s_region = 'AMERICA'::bpchar) -> Hash (cost=72.56..72.56 rows=2556 width=8) -> Seq Scan on date1 (cost=0.00..72.56 rows=2556 width=8) (17 rows) 2014
  11. Custom-Scan APIs(3/5) 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 14 ssbm=# explain

    select sum(lo_revenue), d_year, p_brand1 from lineorder, date1, part, supplier where lo_orderdate = d_datekey and lo_partkey = p_partkey and lo_suppkey = s_suppkey and p_category = 'MFGR#12’ and s_region = 'AMERICA’ group by d_year, p_brand1; QUERY PLAN ------------------------------------------------------------------------------------------------------------ HashAggregate (cost=30939287.03..30939374.53 rows=7000 width=46) Group Key: date1.d_year, part.p_brand1 -> Custom Scan (GpuPreAgg) on lineorder (cost=30939164.53..30939234.53 rows=7000 width=46) GPU Projection: pgstrom.psum(lineorder.lo_revenue), date1.d_year, part.p_brand1 GPU Join Quals [1]: (part.p_partkey = lineorder.lo_partkey) ... [nrows: 6000026000 -> 236602000] GPU Outer Hash [1]: lineorder.lo_partkey GPU Inner Hash [1]: part.p_partkey GPU Join Quals [2]: (supplier.s_suppkey = lineorder.lo_suppkey) ... [nrows: 236602000 -> 47146910] GPU Outer Hash [2]: lineorder.lo_suppkey GPU Inner Hash [2]: supplier.s_suppkey GPU Join Quals [3]: (date1.d_datekey = lineorder.lo_orderdate) ... [nrows: 47146910 -> 47146910] GPU Outer Hash [3]: lineorder.lo_orderdate GPU Inner Hash [3]: date1.d_datekey GPU Group Key: date1.d_year, part.p_brand1 GPU-Direct SQL: enabled (N=2,GPU0,1) -> Custom Scan (GpuScan) on part (cost=100.00..30481.17 rows=78867 width=14) GPU Projection: p_brand1, p_partkey GPU Scan Quals: (p_category = 'MFGR#12'::bpchar) [rows: 2000000 -> 78867] GPU-Direct SQL: enabled (N=2,GPU0,1) -> Custom Scan (GpuScan) on supplier (cost=100.00..190276.56 rows=1992611 width=6) GPU Projection: s_suppkey GPU Scan Quals: (s_region = 'AMERICA'::bpchar) [rows: 9999718 -> 1992611] GPU-Direct SQL: enabled (N=2,GPU0,1) -> Seq Scan on date1 (cost=0.00..72.56 rows=2556 width=8) (24 rows) 2014
  12. Custom-Scan APIs(4/5) 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 15 ▌FDWとCustomScanの違い 

    FDWはデータソース(What)を多様化する。  CustomScanはPostgreSQLテーブルを読み出す 方法(How)を多様化する。 ▌開発の副産物  JOINのパスを追加するためのフック  GROUP-BY等のパスを追加するためのフック ➔postgres_fdwのremote join pushdownなど  Background worker process ➔ CUDA C++のコードを実行時コンパイルするために 提案した機能 2014
  13. Custom-Scan APIs(5/5) 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 16 現在では、PG-Strom以外にもかなりのDBエンジンで利用されている Noriyuki

    Shinoda『列指向アクセスメソッド徹底比較』, PostgreSQL Conference Japan 2004 https://speakerdeck.com/nori_shinoda/postgresql-conference-japan-2024-a4-comparison-of-column-oriented-access-methods 2024
  14. GPU-Direct SQLの着想と開発(1/4) GPUコア GPU Device Memory CPU Host Memory ストレージ

    (HDD/SSD) CPU 720GB/s 16GB/s 0.5GB/s 60GB/s NVME-SSD 一台あたり 3GB/s (当時の)PG-Stromを含む、 GPU-DBはデータがオンメモリ前提 ストレージに落ちたら「負け」 一方この頃、NVME-SSD製品が登場 安価な高速SSDがブレイクの兆し。 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 18 2015
  15. GPU-Direct SQLの着想と開発(2/4) 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 19 DMAコントローラは物理アドレスに対してデータを投げる 物理アドレス空間

    論理アドレス空間 process-X process-Y 0x000000000000 PCIデバイス 0x037000000000 PCI-E Bar1 Linux kernel 0x038000000000 NVME-SSD上のブロック xxx 番から 20ブロック分を読み出して、 物理アドレス0x00... へと転送せよ NVME-SSD上のブロック xxx 番から 20ブロック分を読み出して、 物理アドレス0x37... へと転送せよ NVME READ BlkNo: xxxx Length: 20 Dest: 0x00.... NVME READ BlkNo: xxxx Length: xxx Dest: 0x037.... 2015
  16. GPU-Direct SQLの着想と開発(3/4) ✓ GPU-Direct SQL(当時は SSD-to-GPU Direct SQL)により、メモリサイズを越えた 大量データ(数TB~)を処理する事が可能に。 ➔

    他のGPU-DB製品と比べ、この特徴がPG-Stromを「ストレージとの密結合」という “異質な”進化をするきっかけに。 実験用に購入した Intel SSD 750 (400GB) の 理論帯域まで出ている (!) 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 20 2016
  17. GPU-Direct SQLの着想と開発(4/4) 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 21 同等の機能が、CUDA Toolkit

    11.4で標準機能化し、 多くのストレージベンダの対応も。 ➔ これで独自ドライバの保守から解放される! 2021 2017 GPU Technology Conference 2017において、 “An intelligent storage for PostgreSQL database” と題してポスター発表。 ➔ Top-5 Postersとして選出される。
  18. GPU-Direct SQL機構(1/3) PCI-E Bus Buffer Copy Buffer Copy SCAN JOIN

    GROUP BY Storage Block Read 大量の ”ゴミデータ” も含む 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 22
  19. GPU-Direct SQL機構(2/3) P2P-DMAを利用し、NVME-SSDとGPUを直結してデータ転送 PCI-E Bus SCAN JOIN GROUP BY Storage

    Block Read by NVIDIA GPUDirect Storage P2P-DMA P2P-DMA : Peer-to-Peer Direct Memory Access 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 23
  20. GPU-Direct SQL機構(3/3) Supermicro 4029GP-TRT CPU: Xeon Gold 6226 (2.7GHz, 12C)

    x2 RAM: 192GB (16GB DDR4-2666) x12 GPU: NVIDIA Tesla V100 (5120C, 16GB) x4 SSD: Intel SSD DC P4510 (1.0TB, U.2) x16 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 24 2019
  21. Apache Arrowとは(1/5) 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 26 ▌特徴 

    構造型・列指向で分析用途向けに設計されたデータ形式  アプリケーションによらず、共通のデータ交換形式として利用可能  整数、実数、日付時刻、文字列など基本的なデータ型を定義 NVIDIA GPU PostgreSQL / PG-Strom
  22. Apache Arrowとは(2/5) $ psql postgres : postgres=# IMPORT FOREIGN SCHEMA

    f_part FROM SERVER arrow_fdw INTO public OPTIONS (file '/opt/arrow/ssbm_part.arrow'); IMPORT FOREIGN SCHEMA postgres=# SELECT * FROM f_part LIMIT 5; p_partkey | p_name | p_mfgr | p_category | p_brand1 | p_color | p_type | p_size | p_container -----------+----------------+--------+------------+-----------+-----------+-------------------------+--------+------------- 1 | lace spring | MFGR#1 | MFGR#11 | MFGR#1121 | goldenrod | PROMO BURNISHED COPPER | 7 | JUMBO PKG 2 | rosy metallic | MFGR#4 | MFGR#43 | MFGR#4318 | blush | LARGE BRUSHED BRASS | 1 | LG CASE 3 | green antique | MFGR#3 | MFGR#32 | MFGR#3210 | dark | STANDARD POLISHED BRASS | 21 | WRAP CASE 4 | metallic smoke | MFGR#1 | MFGR#14 | MFGR#1426 | chocolate | SMALL PLATED BRASS | 14 | MED DRUM 5 | blush chiffon | MFGR#4 | MFGR#45 | MFGR#4510 | forest | STANDARD POLISHED TIN | 15 | SM PKG (5 rows) $ python >>> import pyarrow as pa >>> X = pa.RecordBatchFileReader("/opt/arrow/ssbm_part.arrow") >>> Y = X.get_batch(0) >>> Y.slice(0,5) : ---- p_partkey: [1,2,3,4,5] p_name: ["lace spring","rosy metallic","green antique","metallic smoke","blush chiffon"] p_mfgr: ["MFGR#1","MFGR#4","MFGR#3","MFGR#1","MFGR#4"] p_category: ["MFGR#11","MFGR#43","MFGR#32","MFGR#14","MFGR#45"] p_brand1: ["MFGR#1121","MFGR#4318","MFGR#3210","MFGR#1426","MFGR#4510"] p_color: ["goldenrod","blush","dark","chocolate","forest"] p_type: ["PROMO BURNISHED COPPER","LARGE BRUSHED BRASS","STANDARD POLISHED BRASS","SMALL PLATED BRASS","STANDARD POLISHE...] p_size: [7,1,21,14,15] p_container: ["JUMBO PKG","LG CASE","WRAP CASE","MED DRUM","SM PKG"] 同じデータをゼロコピーで別々のアプリケーションから参照できる 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 27
  23. Apache Arrowとは(3/5) Header “ARROW1¥0¥0” Schema Definition Footer Schema Definition Custom

    Metadata Apache Arrow File RecordBatch-1 RecordBatch-k RecordBatch-N Terminator “ARROW1” RecordBatch: 長さの同じ配列を 列ごとに寄せ集め たもの。 Schema Definition: 列名やデータ型、属性が 列の数だけ列挙されている。 テーブル定義に相当する。 A列 B列 C列 D列 物理的な(ファイル上の)レイアウト A列 NULL-Bitmap A列 Values-array B列 NULL-Bitmap B列 Values-index B列 Values-body C列 NULL-Bitmap C列 Values-array D列 NULL-Bitmap D列 Values-array Record Batch-k SELECT SUM(D) FROM f_arrow_tbl WHERE B LIKE ‘%abc%’; 被参照列のみの ロードが容易 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 28
  24. Apache Arrowとは(4/5) 補足:可変長データについて B[0] = ‘dog’ B[1] = ‘panda’ B[2]

    = NULL B[3] = ‘capybara’ B[4] = ‘cat’ B列 Null-Bitmap B列 Values-Index B列 Values-Body 1 1 0 3 ‘d’ ‘o’ ‘g’ ‘p’ ‘a’ ‘n’ ‘d’ ‘a’ ‘c’ ‘a’ ‘p’ ‘y’ ‘b’ ‘a’ ‘r’ ‘a’ 8 8 ‘c’ ‘a’ ‘t’ 0 1 1 16 19 文字列長 3-0=3 文字列長 8-3=5 文字列長 16-8=8 文字列長 19-16=3 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 29
  25. Apache Arrowとは(5/5) データ型のマッピング Apache Arrowデータ型 PostgreSQLデータ型 補足説明 Int int1, int2,

    int4, int8 int1 is an enhancement of PG-Strom FloatingPoint float2, float4, float8 float2 is an enhancement of PG-Strom Binary bytea Utf8 text Bool bool Decimal numeric Date date adjusted to unitsz = Day Time time adjusted to unitsz = MicroSecond Timestamp timestamp timestamptz adjusted to unitsz = MicroSecond Interval interval List array types Only 1-dimensional array is supportable Struct composite types FixedSizeBinary char(n) 大半のデータ型はApache Arrow  PostgreSQLの間で変換可能 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 30
  26. ArrowとParquetの比較(1/2) Arrow形式 Parquet形式 カテゴリ 列指向構造化データ 列指向構造化データ データ編成の単位 RecordBatch RowGroups 基本データ型

    IntやStringなど21種類 IntやStringなど14種類 配列・複合型 ✓ ✓ 更新処理 追記のみ 追記のみ データ圧縮 基本的に無圧縮 ※Record Batch単位の圧縮オプションが あるにはあるが…。 圧縮マニア ※zstd, gzipなど多様な圧縮オプション ※RowGroups単位でデータ圧縮 適したストレージ RAMやNVMEなど高速ストレージ ※ データコピーや解凍時間が許容できない ケースで有用。 帯域がボトルネックとなるような低速 ストレージ 利用シーン ✓ とにかく高速にCPU/GPUへデータ を供給したい。 ✓ ストレージを潤沢に利用する事が できる。 ✓ ストレージとCPU/GPU間の帯域を 節約したい。 ✓ ストレージの利用量を抑えたい 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 31
  27. ArrowとParquetの比較(2/2) ssbm=# ¥d+ List of relations Schema | Name |

    Type | Owner | Persistence | Access method | Size | Description --------+------------------+-------+--------+-------------+---------------+---------+------------- public | customer | table | kaigai | permanent | heap | 4061 MB | public | date1 | table | kaigai | permanent | heap | 416 kB | public | lineorder | table | kaigai | permanent | heap | 876 GB | <-- ★ public | part | table | kaigai | permanent | heap | 229 MB | public | supplier | table | kaigai | permanent | heap | 1318 MB | ✓ SSBMのlineorderテーブルを Arrow/Parquet 両形式でダンプしてみる。 $ ls -lh *as_is* -rw-r--r--. 1 kaigai users 1.2T Nov 2 01:04 f_lineorder.as_is.arrow -rw-r--r--. 1 kaigai users 193G Nov 2 01:21 f_lineorder.as_is.parquet ➔ Parquet圧縮の効果で、Arrowの1/6のサイズにまで小さく。 ただし、Arrowの肥大化は numeric ➔ Arrow::Decimal128 型変換の影響も大きい。 大きな値の必要のないデータをInt32に切り詰めれば…。 $ ls -lh *cast* -rw-r--r--. 1 kaigai users 503G Nov 2 10:28 f_lineorder.cast.arrow -rw-r--r--. 1 kaigai users 139G Nov 2 10:31 f_lineorder.cast.parquet データ圧縮による効果 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 32
  28. Arrow/Parquetを使ってやりたい事 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 33 大量のIoT/M2MログデータをPostgreSQLを用いて検索・集計したい。 Manufacturing Home

    electronics Logistics Mobile Log collector DB Server DB Admin BI Tools (Visualization) AL/ML (異常検知など) 外部ツールからのデータ インポートが非常にシンプル ✓ 使い慣れたSQLによる検索・集計 ✓ TBを越える大量のログデータと、 DB管理されたマスタデータの突合・検索
  29. 補足:FDW(Foreign Data Wrapper)について 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 34 

    文字通り、外部のデータを読み(書き)するためのAPI群  PostgreSQL v8.4の頃から存在する由緒正しい機能  形式の異なる外部データを、PostgreSQLの内部データ形式に変換する ことで、あたかもテーブルがそこに存在するかのように扱うための機能 SQLパーサ オプティマイザ エグゼキュータ クエリ木 (内部形式) 実行計画 SQL構文 問い合わせ結果 buffer manager transaction control metadata cache IPC & Lock index access transaction logs GetForeignPaths() GetForeignPlan() FDW モジュール • 実行計画を作成 • 実行開始 • 次の1行を返す • 実行終了 BeginForeignScan() IterateForeignScan() EndForeignScan() External RDBMS CSV Files PostgreSQLの 共通インフラ
  30. Arrow_Fdw(1/4) Arrow_Fdwを介してPostgreSQLでも Arrow / Parquet の読み出しが可能 postgres=# CREATE FOREIGN TABLE

    f_mytest ( id int, ts timestamp, x float8, y text, z numeric ) SERVER arrow_fdw OPTIONS (file '/tmp/mytest.arrow'); CREATE FOREIGN TABLE postgres=# SELECT * FROM f_mytest; id | ts | x | y | z ----+----------------------------+--------------------+--------------+--------- 1 | 2022-08-02 00:34:44.210589 | 77.4344383633856 | 65ac7f6 | 38.6218 2 | 2019-05-11 03:06:16.353798 | 95.33235230265761 | 9105319395 | 51.8267 3 | 2015-01-04 11:02:25.66779 | 93.67415248121794 | b56930f7834 | 84.9033 : : : : : 24 | 2022-09-24 06:26:02.058316 | 17.668632938372266 | c5e35 | 55.9739 25 | 2016-08-08 18:16:12.248363 | 92.2211769466387 | fa889dd51692 | 19.246 (25 rows) 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 35
  31. Arrow_Fdw(2/4) ▌構文 CREATE FOREIGN TABLE table_name ( colname_1 type_1, colname_2

    type_2 OPTIONS (field ‘field_name’), : : ) SERVER arrow_fdw OPTIONS (file ‘/path/to/arrow_or_parquet_file’); ▌オプション  file 1個の Arrow/Parquet 形式ファイルを指定する  files 1個以上の Arrow/Parquet形式ファイルをカンマ区切りで指定する  dir 指定したディレクトリ配下のファイル全てをマップする。  pattern dirと併用し、ワイルドカードを含むファイル名のパターンを指定する。 (Virtual Column機能については後述)  parallel_workers パラレルクエリを使用する際の並列度を指定する。  field 列をマップする Arrow ファイルのフィールド名を指定する。 何も指定しないと、列名と同じフィールドをマップする。 ※ データ型はArrowのフィールドと互換性のある型でなければならない。 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 36
  32. Arrow_Fdw(3/4) ▌構文 IMPORT FOREIGN SCHEMA table_name FROM SERVER arrow_fdw INTO

    public OPTIONS (file ‘/path/to/arrow_or_parquet_file’);  Arrow/Parquetのスキーマ定義情報から、PostgreSQLのテーブル定義を自動生成する。 postgres=# IMPORT FOREIGN SCHEMA f_mytest FROM SERVER arrow_fdw INTO public OPTIONS (file '/opt/arrow/mytest.arrow'); IMPORT FOREIGN SCHEMA postgres=# ¥d f_mytest Foreign table "public.f_mytest" Column | Type | Collation | Nullable | Default | FDW options --------+-----------------------------+-----------+----------+---------+------------- id | integer | | | | ts | timestamp without time zone | | | | x | double precision | | | | y | text | | | | z | numeric | | | | Server: arrow_fdw FDW options: (file '/opt/arrow/mytest.arrow’) 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 37
  33. Arrow_Fdw(4/4) Parquetファイルを指定する時は、単にParquetファイルを指定すればよい。 postgres=# IMPORT FOREIGN SCHEMA f_small_lineorder FROM SERVER arrow_fdw

    INTO public OPTIONS (dir '/tmp/mydata'); IMPORT FOREIGN SCHEMA postgres=# explain select count(*),sum(lo_revenue),lo_shipmode from f_small_lineorder group by lo_shipmode; QUERY PLAN ------------------------------------------------------------------------------------ HashAggregate (cost=8750.00..8752.00 rows=200 width=48) Group Key: lo_shipmode -> Foreign Scan on f_small_lineorder (cost=0.00..5000.00 rows=500000 width=36) referenced: lo_revenue, lo_shipmode file0: /tmp/mydata/small_lineorder_1996.parquet (read: 0B, size: 983.01KB) file1: /tmp/mydata/small_lineorder_1995.parquet (read: 0B, size: 982.03KB) file2: /tmp/mydata/small_lineorder_1997.parquet (read: 0B, size: 983.05KB) file3: /tmp/mydata/small_lineorder_1993.parquet (read: 0B, size: 982.85KB) file4: /tmp/mydata/small_lineorder_1994.parquet (read: 0B, size: 982.79KB) (9 rows) postgres=# select count(*),sum(lo_revenue),lo_shipmode from f_small_lineorder group by lo_shipmode; count | sum | lo_shipmode -------+--------------+------------- 71645 | 260500947351 | SHIP 71851 | 261493010885 | REG AIR 71216 | 260099033301 | FOB 70923 | 257677021122 | RAIL 71610 | 259668751117 | AIR 71326 | 258375517386 | TRUCK 71429 | 258348920853 | MAIL (7 rows) 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 38
  34. v6.1時点のParquet処理性能 ✓ Arrowの場合、NVME-SSD ➔ GPUへ直接データを流し込んでおり、むしろ GPUの計算能力の方がネックとなっている。 ✓ Parquetの場合、圧縮データをCPU上のlibparquetで展開せねばならない分、 (マルチスレッド処理とはいえ)CPUネックになっていると考えられる。 ✓

    加えて、初期実装ゆえのAPI利用方法の不味さも・・・。 無圧縮の列データをフルスピードで並列演算器に流し込めば、速い。 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 40
  35. ボトルネックの考察 ▌Parquetが遅かったのはなぜ?  NVME-SSDを8本も束ねて使うような サーバはそうそう多くない。 ➔ ストレージがボトルネックではなかった。 ▌ボトルネックの考察  ストレージ帯域

    ✓ 伝統的な性能ネック。NVME-SSDや列データの 利用によって解消しやすい。  圧縮データの展開 ✓ CPUサイクルを犠牲にしてストレージ帯域を ケチる。Parquetのアプローチ。  PCI-Eバス帯域 ✓ 細かな単位でCPUGPUのページ移動が発生 すると、GPUまでストールするので、地味に 注意が必要。  SQL処理(並列計算) ✓ GPU処理能力以上のペースでデータが入力さ れると、当然、GPUも処理ボトルネックに。 データのロード (ストレージ帯域) データのロード (PCI-Eバス帯域) SQL処理 (並列計算) 圧縮データの 展開 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 41
  36. Parquet Cacheのアイデア 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 42 データのロード (ストレージ帯域)

    データのロード (PCI-Eバス帯域) SQL処理 (並列計算) 圧縮データの 展開 初回は やむなし 解凍した無圧縮データ を、非同期でローカル のNVME-SSDに書き込む。 次回以降は、無圧縮+ GPU-Direct SQLという 最速パターンに。 工夫:キャッシュへの書き込みは O_DIRECT付きで行い、Page Cacheを 汚染しない。
  37. Parquet Cache(1/4) キャッシュ単位 Row Group 1 Parquetファイル Row Group 2

    Row Group N Row Group k 列Aデータ 列Bデータ 列Cデータ 列Dデータ キャッシュ単位 • st_dev, st_ino(ファイル識別子) • st_mtim(最終更新時刻) • row_group_id • field_id ➔ ファイル上のブロックを割り当て Row-GroupおよびField単位で キャッシュするため、 列B・列Cだけがキャッシュされ ている状況で、次に列A~列Cを 読み出すクエリを実行する場合、 列B・列Cはキャッシュから、 列AだけをParquetファイルから 読み出せばよい。 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 43
  38. Parquet Cache(2/4) キャッシュ書込み処理 44 parquetReadOneRowGroup GPU-Serviceからの呼び出し parquetCacheLookup() キャッシュ管理データ (共有メモリ上) 検索

    キャッシュファイル(NVME-SSD上) 全部 ヒット 一部 ヒット parquet::arrow::FileReader kern_data_store kern_data_store ファイル 読み出し 呼び出し元へ GPUバッファのポインタを返却 Parquet cache async write worker threads arrow::Table arrow::Table 非同期書込み キューへ投入 • ブロックの割当て (修正LRUによるeviction) • O_DIRECT書込みでPage Cacheを 汚染しない。 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~
  39. Parquet Cache(3/4) ベンチマーク環境 45 ベンチマーク環境・システム構成 ▌saba.heterodb.in ✓ 筐体 Supermicro AS-2015CS-TNR

    ✓ CPU EPYC 9254 (24C; 2.9GHz) x1 ✓ RAM 16GB DIMM (DDR5-4800; ECC) x12 ✓ GPU NVIDIA H100 (PCI-E; 80GB) x1 ✓ NVME Intel D7-P5510 [3.84TB; PCI-E 4.0] x8 KIOXIA CD8P-R [1.92TB; PCI-E 5.0] x4 ✓ N/W Mellanox Connect X-6 [100Gb, 2-Port] x1 ▌aji.heterodb.in ✓ 筐体 Supermicro AS-2015CS-TNR ✓ CPU EPYC 9334 (32C; 2.7GHz) x1 ✓ RAM 16GB DIMM (DDR5-4800; ECC) x12 ✓ GPU RTX PRO6000 BW MAX-Q (PCI-E; 96GB) x2 ✓ NVME KIOXIA CD8P-R [1.92TB; PCI-E 5.0] x4 ✓ N/W Mellanox Connect X-6 [100Gb, 2-Port] x1 GPU/DBサーバ NFSサーバ Parquet Cache用 100Gb Ethernet 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~
  40. Parquet Cache(4/4) ベンチマーク 46 SSBMによるベンチマーク。低速ディスク(NFS)上のParquet読み出しが、2~3回目以降、 ローカルNVME-SSD上のArrowに匹敵する速度を発揮している。 同一の列を参照する クエリを3パターン 実行。回数が進むと キャッシュヒット率

    が上がり、ほぼ、 NVME上のArrowと 同等の性能 Q1_*, Q2_*, ... でそれぞれ参照する列が違うため、 初回のみ、NVME-SSDへの書き込みが発生している。 2回目以降はGPU-Direct SQLによる高速な読み出し。 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~
  41. キャッシュの管理(1/3) ▌キャッシュされた「データ」は、ディスク上の固定長ブロックに分割して格納 ▌管理データ構造は共有メモリ上に保持する構造 ✓ 管理データの更新は低コスト、PostgreSQLの再起動でキャッシュは初期化される ディスク上のブロック割当て 共有メモリ上の管理データ構造 LRU Head Hash

    Slots Free List 管理データ構造1エントリ = ディスク上の1ブロック キャッシュ単位 • ファイル識別子(st_dev / st_ino / st_mtim) • ParquetのRow-Group-ID • ParquetのField-ID(列番号) 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 47
  42. キャッシュの管理(2/3) ▌割り当て可能なブロックがなくなったら? ➔ LRUアルゴリズムに基づいて回収、、、だが  最悪ケースは、巨大なParquetファイルをスキャンした際に、先頭付近をキャッシュした あと、末尾付近をキャッシュするためにすぐに破棄されるシナリオ。  そもそも論、キャッシュできなかったらキャッシュできなかったで「別に構わない」 ▌Parquet

    Cacheの修正LRU  基本、LRUの後ろから解放できるブロックを探す。  最終アクセス時刻が直近のものは候補から除外してギブアップ ✓ pg_strom.parquet_cache_eviction_min_seconds (default: 10min) ✓ pg_strom.parquet_cache_eviction_max_seconds (default: 120min)  アクセス回数1回ごとに最終アクセス時間にボーナス加算 ⇒アクセス頻度の高いキャッシュは(相対的に)排除されなくなる ✓ pg_strom.parquet_cache_eviction_bonus (default: 2.0sec) LRU Head キャッシュ回収に関連する要素 • Reference Counter • 最終アクセス時刻 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 48
  43. キャッシュの管理(3/3) $ pg_ctl restart : 2026-05-27 10:42:00.141 JST [2526805] LOG:

    Parquet cache file [/opt/arrow/pgstrom_parquet.cache] (size: 800GB, block: 2MB, nslots: 33695) : $ ls -lh /opt/arrow/pgstrom_parquet.cache -rw-------. 1 kaigai kaigai 800G May 27 10:42 /opt/arrow/pgstrom_parquet.cache Parquet Cache設定パラメータ ✓ pg_strom.parquet_cache_path (default: none) キャッシュファイルのパスを設定する。現状では1個だけ。 ✓ pg_strom.parquet_cache_size (default: 160GB) キャッシュファイルのサイズを設定する。起動時にこのサイズのファイルを作成する。 ✓ pg_strom.parquet_cache_unitsz (default: 2MB) キャッシュを分割する固定長ブロックのサイズ。 ✓ pg_strom.parquet_cache_eviction_min_seconds (default: 10min) ✓ pg_strom.parquet_cache_eviction_max_seconds (default: 120min) ✓ pg_strom.parquet_cache_eviction_bonus (default: 2sec) 前述の通り、キャッシュ回収の修正LRUアルゴリズムに関連するパラメータ。 ✓ pg_strom.parquet_cache_target_usage (default: 98) キャッシュのブロック割当て率がこの値を越えると、先回りしてキャッシュ回収処理が走る。 ✓ pg_strom.parquet_cache_max_async_write (default: 80) 同時並行書込みの最大値。あまりに書込みキューが長くなるようなら、PG-StromはParquet Cacheへの 書き出しを諦めて、早々にメモリを開放する。 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 49
  44. こういう事がやりたい 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 51 大量のIoT/M2MログデータをPostgreSQLを用いて検索・集計したい。 Manufacturing Home

    electronics Logistics Mobile Log collector DB Server DB Admin BI Tools (Visualization) AL/ML (異常検知など) 外部ツールからのデータ インポートが非常にシンプル ✓ 使い慣れたSQLによる検索・集計 ✓ TBを越える大量のログデータと、 DB管理されたマスタデータの突合・検索
  45. クラウドとPG-Strom(1/2) ▌クラウド環境でPG-Stromが厳しかった理由  ストレージ帯域の問題(EBSではGPUに追い付かない)  ローカルNVME SSDの仕様(再起動で内容が消去されてしまう)  NICのRDMAに対応したインスタンスあ非常に高価 ➔

    ローカルNVME SSDを活用できるParquet Cacheなら? https://dev.classmethod.jp/articles/amazon-ec2-g7e-instance-nvidia-rtx-pro-6000-gpu/ より引用 ココを有効活用できるようになる。 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 52
  46. クラウドとPG-Strom(2/2) S3オブジェクトストレージを低速ストレージと見なし、 Parquet Cacheを使ってPostgreSQL RDSから高速の検索を実現。 PostgreSQL RDS インスタンス GPUサーバ PG-Strom

    コンテナ オンデマンドでの GPU利用で、 コストを抑える S3オブジェクト ストレージ 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 53 Manufacturing Home electronics 使い慣れたPostgreSQLで、 楽々大量データ処理 Log collector ファイルとして 保存された 大量のログデータ
  47. まとめ ▌背景技術  PG-Strom:SQLをGPUにオフロードして超並列実行するための拡張モジュール  GPU-Direct SQL:NVME-SSDからGPUへ直接のデータ転送を行い、 ストレージ帯域の理論上限に近い処理速度を実現する。  Arrow_Fdw:Apache

    Arrow / Parquet ファイルをPostgreSQLの外部表として マップする。ArrowはGPU-Direct SQLにも対応 ▌Parquet Cache  Parquetを読み出す時のボトルネックは2つ。 ① ストレージ帯域(低速ストレージのケース) ② 圧縮データの展開処理(CPUバウンド) ➔では初回は目をつぶり、解凍後の無圧縮データをNVME-SSDにキャッシュすれば、 Arrow_Fdw + GPU-Direct SQLと同じインフラを使用できる。  実際に作ってみた ➔SSBMで計測したところ、Arrow + GPU-Direct SQLに匹敵する実行性能。  今後の予定 ➔S3オブジェクトストレージの直接読み出し、品質改善・安定化 ➔従来は厳しかった PaaS 環境でのPG-Stromの利活用を広げたい。 2026-05-29 PG-Stromセミナー ~PG-StromのParquetを爆速化するParquet NVME Cache~ 54