「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`)が先か、改めて見直してみましょうね。
それでは、また現場でお会いしましょう!
コメント