8 ポイント 投稿者 GN⁺ 2026-01-30 | 3件のコメント | WhatsAppで共有
  • PostgreSQL拡張プロキシのPgDogが、SQLパース性能を高めるためProtobufシリアライズの代わりにRustの直接バインディングを導入
  • 従来のProtobufベース構造を**C–Rust直接変換(bindgen + Claude生成ラッパー)**に置き換え、パース5.45倍、デパース9.64倍の高速化を実現
  • 性能ボトルネックはpg_query_parse_protobuf関数で見つかり、キャッシュを試みた後も根本改善のため構造変更を実施
  • Claude LLMを活用して6,000行のRust–C変換コードを自動生成し、parsedeparsefingerprintscanなど主要関数に適用
  • この最適化により、PgDogのCPU使用量とレイテンシが低下し、PostgreSQL水平スケーリングプロキシとしての効率が大幅に向上

PgDogとProtobufの限界

  • PgDogはPostgreSQLをスケールさせるためのプロキシで、内部ではlibpg_queryを使ってSQLクエリをパースしている
    • Rustで書かれており、従来はProtobufのシリアライズ/デシリアライズを通じてCライブラリと通信していた
  • Protobufは高速だが、直接バインディング方式のほうがさらに速い
    • PgDogチームはpg_query.rsをフォークしてProtobufを取り除き、C–Rust直接バインディングを実装
    • その結果、クエリパースは5.45倍、デパースは9.64倍高速化した

ベンチマーク結果

  • ベンチマークはPgDogのフォークリポジトリで再現可能
    • pg_query::parse (Protobuf): 613 QPS
    • pg_query::parse_raw (直接C–Rust): 3357 QPS
    • pg_query::deparse (Protobuf): 759 QPS
    • pg_query::deparse_raw (直接Rust–C): 7319 QPS

性能ボトルネック分析とキャッシュの試み

  • samplyプロファイラでCPU使用時間を分析した結果、pg_query_parse_protobuf関数がボトルネックであることが確認された
  • キャッシュによる一部改善も試みた
    • LRUアルゴリズムベースのハッシュマップキャッシュを使い、クエリテキストをキーにASTを保存
    • プリペアドステートメントを使う場合は再利用が可能
  • しかし一部のORMは数千のユニーククエリを生成し、古いPostgreSQLドライバはプリペアドステートメントをサポートしないため、キャッシュ効率は低かった

LLMを活用したProtobufの除去

  • PgDogチームはClaude LLMを活用して、Protobufを除去したRustバインディングを生成
    • 明確で検証可能な作業範囲では、AIは効果的に機能した
  • Claudeはlibpg_queryのProtobuf仕様に基づいてC構造体をRust構造体へマッピング
    • 2日間の反復作業の末、6,000行の再帰的なRustコードが完成
  • parsedeparsefingerprintscan関数に適用し、pgbench基準で25%の性能向上を確認

実装の詳細構造

  • RustとCの間の変換はunsafe関数を使って構造体を直接マッピング
    • C構造体をPostgres APIに渡してASTを生成し、Rustへ再帰変換する
  • 各ASTノードはconvert_node関数で処理され、SQL文法の数百のトークンをマッピング
    • SELECT、INSERTなど各ノードタイプごとに個別の変換関数が存在
  • 変換結果には既存のProtobuf構造体(protobuf::ParseResult)を再利用し、テスト時にバイト単位の比較検証が可能
  • 再帰アルゴリズムはメモリ割り当てが少なくCPUキャッシュ効率が高いため、反復ベース実装より高速
    • 反復ベース実装は不要なメモリ割り当てとハッシュマップ参照により、かえって遅くなる

結論

  • Postgresパーサのオーバーヘッドを減らし、PgDogのレイテンシ、メモリ、CPU使用量をすべて削減
  • この最適化により、PgDogはより高速かつ低コストで運用可能なPostgreSQLスケーリングプロキシへ進化
  • PgDogはPostgreSQLの**水平スケーリング(next iteration)**をともに構築するエンジニアを募集中

3件のコメント

 
a1eng0 2026-01-31

私が原文を曲解しているのかもしれませんが、ことさらに Rust 関連の記事は、本質から離れて、まるで「Rustだから」速くなったかのように書かれている気がします。

今回の記事の主なポイントは、不要なシリアライズのオーバーヘッドを減らしたことで性能が改善した、という点ですよね。

今あらためて見ると、そこまで Rust を称賛する記事でもない気もしますが、ほかの記事の影響で私にネガティブな印象ができてしまっているのでしょうか?

 
xguru 2026-01-31

私もこれ、元記事のタイトルが実際の内容と違って Rust に寄りすぎていて、性能向上に焦点を当てているように見えたので、少し修正しました。
Rust の記事はそういう傾向がよく見られるので、少しフィルタリングしながら読む必要はある気がします。

 
GN⁺ 2026-01-30
Hacker News の反応
  • タイトルだけ見ると Rust が 5倍の性能向上 をもたらしたように見えるが、実際には遅くなっていたというのが皮肉
    問題は、Rust で書かれたソフトウェアが C 製の libpg_query を使う必要があったものの、直接接続できず、Protobuf ベースの Rust–C バインディングを使っていたこと
    この方式が遅かったため、最終的に LLM の助けを借りて、移植性は低いがはるかに最適化されたバインディングを書き直した
    もし最初から C で書いていれば変換工程は不要だったはず。つまりタイトルは「Rust の利用による性能損失を減らした」のほうが正確だったはず
    変換レイヤーは移植性と安全性をもたらすが、結局 コピー・変換・シリアライズ が繰り返され、アプリを遅くする原因の1つだと思う

    • Rust が遅いのではなく、外部ライブラリの 非効率な設計 が問題だった
      Rust から C ライブラリを呼ぶのは非常に簡単で、安全なラッパーもすでに多く存在する
      Protobuf を間に挟む構成はほとんど見たことがなく、それがボトルネックだった
      タイトルは単にクリックを誘うための「Rust で書き直した」系のミームに近いと思う
    • C で書けばもっと速かったはずというのは公平ではない
      元のライブラリが シリアライズ/デシリアライズ を繰り返す誤った設計になっていて、それを取り除いたのが本質
      タイトルは「Protobuf を通常の API に置き換えたら 5倍速くなった」のほうが正確
    • なぜ最初から FFI を使わなかったのか気になる
      Rust での C バインディングは最も簡単な部類で、大きな API でなければ単純
      Protobuf はメモリ内データ交換には 不適切なツール だと思う
    • LLM で最適化したのなら、いっそ C ライブラリを Rust に 完全移植 するのに使ったらどうだったのかと思う
      今後は LLM のおかげで、さまざまな言語への移植が爆発的に増えそう
    • Rust と Postgres の間に Protobuf を置くのは 性能の悪夢 レベル。そんなライブラリが人気を得たのが驚き
  • タイトルはやや誤解を招く
    実際には「Protobuf のシリアライズ段階を取り除いたら速くなった」という内容

    • Protobuf は単純なコピーでは実現できない バージョン互換性 を提供する
      クライアントとサーバーが独立して更新されても動作できるようにし、複数言語間の通信も容易にする
      大規模システムではこうした柔軟性が非常に重要
    • Protobuf のシリアライズが単純なメモリコピーより5倍遅いというのは、むしろ 思ったより速い 印象
    • memcpymmap のほうがはるかに速いが、Rust 界隈ではそうした unsafe な方式 を嫌う
    • こういう場合は Arrow のような標準化された zero-copy フォーマット を使うとよさそう。言語ごとのパディング問題やセキュリティ検査を自動で処理してくれる
  • Rust のせいではなく、Protobuf を 汎用保存フォーマット として使ったことが遅さの原因かもしれない
    結局のところ、特定の目的に合わせて単純化したのが核心

    • 「Protobuf をネイティブ最適化実装に置き換えた」というタイトルでは注目を集めにくかっただろう
      Rust をタイトルに入れたのはクリック誘導のための選択に見える
    • 記事タイトルは論争を呼ぶが、本文はその点を認識している
    • 実際には Rust とほとんど関係ないが、Rust がなければ メインページに載れなかった だろう
  • pg_query の元の作者が背景を説明している
    もともと pganalyze で Postgres クエリをパースしてテーブル参照を見つけ、クエリを書き換えたり整形したりする用途で使っていた
    初期は JSON を使っていたが、その後 Protobuf に移行 し、複数言語(Ruby、Go、Rust、Python など)で 型安全なバインディング を容易に提供するためだった
    Rust のような言語では FFI のほうがよいが、他の言語では保守負担が大きい
    Lev の試みは支持しており、今後 libpg_query に直接 FFI でアクセスできる関数 を追加する予定
    ただし性能が重要でない場合は、Protobuf が依然としてより 便利な選択肢 でもある

  • 「5倍速い」という言葉で、Cap’n Proto の「無限に速い」という冗談を思い出した

    • Cap’n Proto は Protobuf の作者が作ったもので、パース不要の構造 だからそう表現した
    • ただ、実際に使ってみると Cap’n Proto は 使い勝手が悪い
  • タイトルは大げさだが、実際の作業は印象的
    Protobuf を完全になくしたのではなく、使い方を最適化 したという話
    「X に変えたら 5倍速くなった」という文句は、たいてい「ひどい実装を直した」という意味
    核心となる教訓は

    1. シリアライズ/デシリアライズは 隠れたボトルネック になりやすい
    2. デフォルト実装の多くは、たいてい特定の状況に最適化されていない
    3. プロファイリング によってボトルネックを正確に突き止めるべき
      Rust FFI にもオーバーヘッドはあるため、本当の成果は言語ではなく データフローの再設計 と最適化の努力によるもの
  • FlatBuffers のほうが速いが、Protobuf が使われる理由は 大企業が保守している からだ

    • しかし FlatBuffers も Google が保守している
      結局「Google 製だから安全」という認識には根拠がない
    • 自分も以前 Google プラットフォーム(code.google.com)にコードを置いて痛い目を見たことがある
      単に メモリ共有とバージョンフィールドだけを持つ zero-copy 構造 で十分なのに、あえて Protobuf を使う理由はないと思う
    • Google は今でも 文字列フィールドの zero-copy 最適化 を公開していない
  • Protobuf の性能は 冗談レベル だと思う
    シリアライズが事実上無料な zero-copy フォーマット を使うべき
    たとえば自分が作った Lite³ は FlatBuffers より 242倍速い

    • ただし、そのライブラリが登場したのは 2025年11月以降 だった
      Protobuf が使われるのは、エコシステム、スキーマ、言語ごとのツール群など、数多くの現実的な理由があるから
  • 実際には Rust や Protobuf の問題ではなく、PostgreSQL 抽象化レイヤーの 非効率なシリアライズ実装 が原因だった
    pgdog はそのレイヤーを取り除き、C API で直接データを渡した
    不要な機能を削れば当然速くなる
    ただし、人によっては依然として シリアライズが必要な状況 がある
    そういう人たちに「Rust に変えろ」というタイトルは誤ったメッセージになる
    結局、ほとんどの場合は JSON で十分 で、本当にもっと速さが必要ならシリアライズ自体を避けるべき

  • これは 不公平な比較
    IPC 通信にシリアライズプロトコルを使えば、当然オーバーヘッドがある
    「20%速くなれば改善、10倍速くなれば最初から作り方が間違っていた」という言葉がぴったり当てはまる例