【実務・中級編】 work_mem設定 – PostgreSQL

「ソートが遅い…」と思ったらまず疑うべき。PostgreSQLの `work_mem` との付き合い方

現場でデータベースを触っていると、必ず一度は突き当たる壁があります。「最初は速かったクエリが、データが増えるにつれて急激に遅くなる」という現象です。

その犯人の多くは、実はクエリそのものよりも「PostgreSQLがメモリをケチりすぎていること」にあります。特にソート(ORDER BY)やハッシュ結合(JOIN)のパフォーマンスを左右する `work_mem` は、チューニングの登竜門であり、かつ最も事故りやすいポイントの一つ。

今日は、教科書には載っていない「現場の肌感覚」を交えて、この `work_mem` とどう向き合うべきかをお話しします。

—

work_mem が足りないと何が起きるのか?

PostgreSQLは、ソートやハッシュ結合を行う際、まず `work_mem` で指定されたメモリ領域を使おうとします。もしこの領域にデータが収まりきらなくなるとどうなるか?

答えは「一時ファイル(Temp File)の作成」です。

ディスク(SSDであっても)への書き出しが発生した瞬間、クエリの実行速度はガクッと落ちます。いわゆる「ディスクI/Oのボトルネック」です。これを防ぐためには、可能な限りメモリ上で処理を完結させる必要があります。

現場でよくある「work_mem」の罠

多くの初心者がやりがちなのは、「とりあえず `work_mem` をデカくしておけば速くなるだろ!」という勘違いです。

ここが一番の注意点ですが、`work_mem` は「クエリ全体」ではなく「操作ごと」に消費されます。

例えば、1つの複雑なクエリの中に、ソートが3箇所、ハッシュ結合が2箇所あるとします。この場合、PostgreSQLは最大で `work_mem × 5` のメモリを確保しようとします。もし `work_mem` を 1GB に設定し、同時に 50 人のユーザーがそのクエリを叩いたらどうなるでしょう?

`1GB × 5操作 × 50セッション = 25GB`

はい、物理メモリをあっという間に食い潰して OOM Killer(OSのメモリ保護機能)にプロセスを殺されるか、激しいスワップが発生してサーバー全体が応答不能になります。これが「work_mem を上げすぎてサーバーが落ちた」という悲劇の正体です。

—

実践:適切な値をどう導き出すか?

まず、一時ファイルが作成されているかを確認しましょう。PostgreSQLのログ設定で `log_temp_files` を 0 に設定すれば、一時ファイル作成のログがすべて出力されます。

— ログに出力された一時ファイルのサイズを確認し、目安にする
— 数MB程度なら許容範囲ですが、数百MB〜数GBなら要注意です

推奨されるアプローチ

1. 全体をいじらない: `postgresql.conf` でサーバー全体の設定を極端に上げるのは厳禁です。デフォルトの 4MB は今の時代少し小さいですが、せいぜい 16MB〜64MB 程度に留めるのが無難です。
2. クエリ単位でチューニングする: 特定の重いバッチ処理などがあるなら、そのセッションの中だけで `work_mem` を一時的に増やします。これがプロのやり方です。

— 重いバッチ処理の開始時にだけ適用する
BEGIN;
SET LOCAL work_mem = ‘256MB’;
— ここで重いクエリを実行
SELECT FROM large_table ORDER BY created_at DESC;
COMMIT;

こうすれば、他のセッションに悪影響を与えることなく、そのクエリだけを劇的に速くすることができます。

—

まとめ:メモリは「戦略的」に使うもの

`work_mem` のチューニングは、データベースの性格と、そこで動くクエリの性質を理解することから始まります。「なぜこのクエリはメモリを食うのか?」「インデックスで解決できないソートなのか?」を `EXPLAIN ANALYZE` で見てみてください。

今回のポイント:

  • `work_mem` 不足は一時ファイルによるI/O待ちを招く。
  • 全体設定を上げすぎると、同時実行数によってメモリ不足に陥る。
  • 重いクエリがあるなら、`SET LOCAL` でその時だけメモリを奢る。

データベースエンジニアの仕事は、闇雲に数値をいじることではなく、限られたリソースを「一番必要な場所に、必要なだけ」割り当てることです。

まずは皆さんのサーバーのログを眺めてみてください。ひっそりと「一時ファイルを作っているクエリ」が見つかるはずですよ。そこが、パフォーマンスアップの第一歩です。

コメント

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