23
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

PostgreSQLを使っていると、 「動くけど遅いSQL」や「なぜか重くなる処理」 に遭遇することがあります。

この記事では、実務で遭遇した“重いSQL”を具体的にどう書き直せば高速化できるかを、Before/After形式で紹介します。

  • クエリ最適化の基本
  • 実務で見逃しがちなNGパターン
  • インデックスや集約関数の使い方

など、読んだその日から役立つ知見を詰め込みました。


1. WHERE句で関数を使うとインデックスが効きません

❌ Before:

SELECT * FROM users WHERE to_char(created_at, 'YYYY-MM-DD') = '2024-06-01';

問題点:関数を使用するとインデックスが無効化されます

✅ After:

SELECT * FROM users WHERE created_at >= '2024-06-01' AND created_at < '2024-06-02';

改善点:インデックスが効くよう、日付の範囲指定で記述を変更します


2. OFFSETは重いため、カーソルベースに切り替えましょう

❌ Before:

SELECT * FROM orders ORDER BY created_at DESC OFFSET 10000 LIMIT 20;

問題点:OFFSETが大きいと実質全件スキャンに近くなります

✅ After:

SELECT * FROM orders 
WHERE created_at < '2024-06-01 12:00:00' 
ORDER BY created_at DESC 
LIMIT 20;

改善点:カーソル(ページングの基準値)を使って高速化しています


3. COUNT(*)を速くしたいときは対象を絞りましょう

❌ Before:

SELECT COUNT(*) FROM access_logs;

問題点:巨大テーブルの全件カウントは非常に遅くなります

✅ After:

SELECT reltuples::bigint FROM pg_class WHERE relname = 'access_logs';

改善点:精度よりも速度を優先し、推定件数を取得します


4. EXISTSの代わりにJOIN+LIMIT 1を使うこともできます

❌ Before:

SELECT * FROM users WHERE EXISTS (
  SELECT 1 FROM orders WHERE orders.user_id = users.id
);

問題点:EXISTSは条件によっては非効率です

✅ After:

SELECT DISTINCT users.* FROM users
JOIN orders ON orders.user_id = users.id
LIMIT 1;

改善点:LIMITを使うことで、存在チェックを最小処理で実現します


5. GROUP BYとJOINの順番に注意しましょう

❌ Before:

SELECT u.name, COUNT(o.id)
FROM users u
JOIN orders o ON o.user_id = u.id
GROUP BY u.name;

問題点:JOIN対象のテーブルが巨大だとGROUP BYが重くなります

✅ After:

SELECT name, order_count FROM (
  SELECT user_id, COUNT(*) AS order_count
  FROM orders
  GROUP BY user_id
) o
JOIN users u ON u.id = o.user_id;

改善点:先に集約してからJOINすることで処理量を削減しています


まとめ:遅いSQLには必ず“理由”があります

課題 解決の観点
関数でWHERE句 範囲条件で書き直す
OFFSET地獄 カーソルベースに変える
COUNT全件 推定件数で代替する
EXISTS過多 JOIN+LIMITで代替可能
JOIN+GROUP重複 集約を先に行う

速くなるSQLは、読みやすくなるSQLでもあります。
パフォーマンスは設計の問題であり、構文の問題ではありません。

爆速化のポイントは「当たり前だと思っている構文」を、“実行計画の目線”で見直すことです。


おわりに

PostgreSQLはチューニング性が高い一方で、“気づかなければ損をするポイント”も多くあります。

実務で悩んだとき、この記事が一つの気づきになることを願っています。

23
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?