JIT(Just-In-Time)は、重いSQLの“計算部分”をその場で機械語にコンパイルして速くするしくみです。I/Oがボトルネックの小さなクエリには効きにくいけど、大きめの集計・結合・フィルタでは有効です。
JITって何?なぜ速くなるの?
PostgreSQLのJITは、SQLを実行する中で発生する式評価(WHERE句やJOIN条件、投影、集計関数など)の処理を、実行時にLLVMを使って最適化された機械語に変換します。
これにより、以下のような “CPUでコツコツ計算する” ところが速くなります。
- 複雑なWHERE条件の評価
- JOIN時のキー比較
- 集計(
GROUP BY、集約関数) - たくさんの行に対する式計算(CASE式、関数呼び出し 等)
逆に、ディスクI/Oがメインのなエリ(インデックス1件取りなど)では、JITの“コンパイルにかかるコスト”のほうが上回ってしまい、効果が出にくいです。
まずは現状確認(JITが使える?使われてる?)
-- いまJITがオンかどうか
SHOW jit;
-- JIT関連の全設定を一覧
SELECT name, setting, unit, short_desc
FROM pg_settings
WHERE name LIKE 'jit%';
-- 実行計画でJITが働いたかを確認(JITセクションが出ればOK)
EXPLAIN (ANALYZE, BUFFERS, SUMMARY)
SELECT count(*)
FROM big_table t
JOIN big_table2 s USING(key)
WHERE t.colA > 100 AND s.colB LIKE 'X%';
EXPLAIN結果にこんなセクションが出ていれば、JITが実際に使われています。
JIT:
Functions: 6
Options: Inlining true, Optimization true, Expressions true, Deforming true
補足:JITを使うにはPostgreSQLがLLVMサポート付きでビルドされている必要があります。配布物やOSによっては無効の場合があるので、まずは SHOW jit; で確認しましょう。
まずは3つの設定だけ覚えればOK(入門の設定)
JITはしきい値(コスト)を超えるクエリにだけ働かせるのがコツです。はじめは「重いクエリだけJIT」を目指しましょう。
jit… JITの有効/無効(on/off)jit_above_cost… このコストを超えたらJITを使うjit_optimize_above_cost/jit_inline_above_cost… さらに重い時だけ最適化/インライン展開
おすすめの設定(postgresql.conf or セッション)
-- まずはJITを有効にする
SET jit = on;
-- “ほんとうに重い” クエリだけJIT(しきい値は高めから)
SET jit_above_cost = 200000;
SET jit_inline_above_cost = 300000;
SET jit_optimize_above_cost = 500000;
ポイント
しきい値(cost)は高めから始めて、効果を見ながら下げるのが安全。
小さなコストのクエリにJITを当てないための保険です。
クエリ単位でオン/オフする
-- このトランザクション内のクエリだけJITをオフ
BEGIN;
SET LOCAL jit = off;
SELECT ...; -- 小さなOLTP向け
COMMIT;
-- 逆に、このクエリはJITを強制オンにしたい
SET LOCAL jit = on;
SELECT ...; -- 重い集計
JITはどんな時に効く?
効きやすいケース
数百万~数千万行レコードを参照する大規模集計に有効です。 複雑な式評価や多段のJOINにも効果的です。 I/Oが十分速い(メモリヒットが多い、キャッシュが効く、NVMe等)場合、効果的です。
効きにくい(逆効果となる)ケース
対象が少ないレコード・コストの低いレコードは逆にコンパイルの手間の方に時間がかかる可能性があります。 I/O待ちが支配的なクエリでは効果がありません。(ディスクが遅い、統計が古くプランが悪い) 頻繁に形の違うSQLを都度投げるケースでは毎回コンパイルコスト発生し、場合によっては逆効果です。
かんたん実験レシピ(ベンチの取り方)
-
代表的な重いSQLを1つ選ぶ(業務で実際に遅いもの)
-
統計更新して計画ブレを減らす
ANALYZE; -
JITオフで計測
SET jit = off; EXPLAIN (ANALYZE, BUFFERS, SUMMARY) <重いSQL>; -
JITオン + しきい値低めで計測
SET jit = on; SET jit_above_cost = 0; -- テスト目的で強制的に使わせる EXPLAIN (ANALYZE, BUFFERS, SUMMARY) <同じSQL>; -
実行時間と
JIT:セクションを比較。
短縮率が十分なら、本番ではjit_above_costを高めに戻し、“重い時だけJIT” に落とし込む。
よくある疑問と落とし穴
Q. インデックス検索も速くなりますか?
A. いいえ。JITは計算を速くします。I/Oやインデックス探索自体は別の話。まずはインデックス設計・統計の鮮度を整えること。
Q. 並列実行と一緒に使えますか?
A. 使えます。並列×JITは相性が良く、重い集計でさらに効くことがあります。ただしコンパイル時間も増えるため、しきい値の調整は必須。
Q. メモリは足りますか?
A. JIT自体のメモリは小さめですが、重いクエリ=work_mem消費が増えがち。work_memやmaintenance_work_memなど全体設計の見直しも並行して行いましょう。
現場投入のミニ・ガイド(まずはこれだけ)
- 可用性チェック:
SHOW jit;とpg_settingsで使えるか確認 - 段階導入:
jit = onにして、jit_above_costを高め(例:200,000)に - 効果測定:重い代表SQLを JIT on/off でEXPLAIN ANALYZE比較
- しきい値調整:効果が高いなら
jit_above_costを少し下げて適用範囲を広げる - ピンポイント運用:小さなOLTPは
SET LOCAL jit = off;でガード
まとめ
JITは「重い計算を速くするスイッチ」です。重いSQLの“計算部分”をその場で機械語にコンパイル、計算速度を早くします。I/Oが多い小さなクエリには効きにくいため、しきい値を高めにして重い処理だけ当てるようにしましょう。
EXPLAIN (ANALYZE) の JITセクションで “効いているか” を必ず確認し、不要なコンパイルが走らないようにしましょう。小さく(コスト高めのSQLのみ)導入して、効果の高いところに集中適用するのが現場最適です。
チートシート
-- 現状確認
SHOW jit;
SELECT * FROM pg_settings WHERE name LIKE 'jit%';
-- とりあえずオン(重い時だけ)
SET jit = on;
SET jit_above_cost = 200000;
SET jit_inline_above_cost = 300000;
SET jit_optimize_above_cost = 500000;
-- クエリ単位の切り替え
SET LOCAL jit = off; -- 小さいOLTP
SET LOCAL jit = on; -- 重い集計
-- 実測(JITが効いたか確認)
EXPLAIN (ANALYZE, BUFFERS, SUMMARY) <SQL>;

0 件のコメント:
コメントを投稿