【実務・中級編】 JITコンパイル (LLVM) – PostgreSQL

「PostgreSQLのJIT、とりあえずOFFにしてない?」――現場で役立つチューニングの深淵

こんにちは。現場でPostgreSQLと格闘し続けているエンジニアです。

今日は、PostgreSQLのパフォーマンスチューニングにおいて、多くのエンジニアが「結局なんなのかよく分からないから、とりあえず`jit = off`にしている」という、あのJIT(Just-In-Time)コンパイルについて深掘りしようと思います。

正直に言います。JITは「魔法のボタン」ではありません。しかし、特定の重たいクエリに対しては、劇的なブーストをかけてくれる相棒にもなります。その仕組みと、現場でどう付き合うべきか、一緒に見ていきましょう。

—

そもそも、PostgreSQLのJITは何をしているのか?

通常、PostgreSQLはクエリを実行する際、あらかじめ用意された「インタープリタ」を使って式を評価します。SQLを実行するたびに、CPUが「この演算は何か? 次の演算は何か?」と逐一判断しながら動くわけです。

これに対し、JITコンパイル(LLVMを使用)は、クエリを解析した瞬間に、そのクエリ専用の機械語をその場で生成してしまいます。

例えるなら、「毎回マニュアルを見ながら料理する」のが通常実行で、「その料理専用の自動調理プログラムを書いて、マシーンに実行させる」のがJITです。複雑な計算や、大量の行を処理する集約処理であれば、後者の方が圧倒的に速いのは想像に難くないですよね。

—

実践:どんな時に効果が出るのか

JITは「万能ではない」と最初に言いました。なぜなら、コンパイルそのものにもコストがかかるからです。

1. JITが真価を発揮するケース

  • 大規模な集約処理: `GROUP BY` や `DISTINCT` で数百万行を扱うとき。
  • 複雑な式: `WHERE` 句の中に計算式がゴロゴロ入っているようなクエリ。
  • 大規模なJOIN: 結合条件が複雑で、評価コストが高い場合。

2. 逆にJITが「足かせ」になるケース

  • 単純なクエリ: `SELECT FROM users WHERE id = 1` のような、一瞬で終わるクエリ。コンパイルする時間の方が長くなってしまいます。
  • OLTP環境: 短いクエリがひっきりなしに飛んでくる環境では、JITは単なるオーバーヘッドになります。

—

JITを制御する「3つのつまみ」

設定ファイル(`postgresql.conf`)にあるこれらを見てみてください。ここを理解するのがチューニングの第一歩です。

JITの有効化/無効化
jit = on

JITコンパイルが発動する「コスト」の閾値
jit_above_cost = 100000

インライン化(関数呼び出しを最適化)が発動する閾値
jit_inline_above_cost = 500000

最適化の強さ(コンパイル時間と実行速度のトレードオフ)
jit_optimize_above_cost = 500000

先輩からのアドバイス:
いきなり全部変えるのではなく、まずは `jit_above_cost` を調整してみてください。デフォルトの `100000` は、少し小さめです。これだと、そこまで重くないクエリまでコンパイルが走ってしまい、全体のレイテンシが悪化することがあります。

試しに、`200000` や `500000` に上げてみて、`EXPLAIN ANALYZE` で実行時間を比較してみてください。劇的に改善するクエリと、そうでないクエリが見えてくるはずです。

—

現場で役立つ「JIT確認コマンド」

クエリが実際にJITを使っているかどうかは、`EXPLAIN ANALYZE` を叩けば一発でわかります。

EXPLAIN ANALYZE SELECT sum(price) FROM orders WHERE status = ‘delivered’;

実行結果の最後に、こんな行が出てきませんか?

> JIT:
> Functions: 12
> Options: Inlining true, Optimization true, Expressions true, Deforming true
> Timing: Generation 1.2ms, Inlining 5.4ms, Optimization 15.2ms, Emission 12.1ms, Total 33.9ms

もし「Timing」の数字が、実際のクエリ実行時間に対して無視できない大きさなら、JITの閾値を引き上げる検討が必要です。

—

結論:どう向き合うべきか

「JITは悪」と決めつけるのは、宝の持ち腐れです。

1. 基本はONで良い: 近年のPostgreSQL(v12以降)はだいぶ賢くなっています。
2. バッチ処理なら最強: 夜間のデータ集計や、分析用クエリが遅いなら、まずJITの恩恵を疑ってください。
3. OLTPなら慎重に: ユーザーからのレスポンスを重視するWebアプリなら、まずは `jit = off` を試して、ベースラインと比較する。

結局、データベースチューニングは「自分のアプリケーションが何を得意としているか」を知る旅です。今日紹介したパラメータをいじりながら、自分の環境に最適な「スイートスポット」を探してみてください。

もし、「JITの設定をいじっても改善しない!」という沼にハマったら、インデックス設計や統計情報の更新(`ANALYZE`)が先か、改めて見直してみましょうね。

それでは、また現場でお会いしましょう!

コメント

タイトルとURLをコピーしました