まずクエリプランを見て、最大のコストを修正します。 EXPLAIN/EXPLAIN ANALYZE を使ってデータベースが実際に何をしているかを確認し、適切なインデックスを追加し、N+1 クエリを排除して、必要なデータだけを選択します。
クエリプランを読む
EXPLAIN ANALYZE は実行プランと実際のタイミングを表示します。大きなテーブル上のSeq Scanは典型的な警告信号です:
sql
EXPLAIN ANALYZE
orders customer_id ;
まずクエリプランを見て、最大のコストを修正します。 EXPLAIN/EXPLAIN ANALYZE を使ってデータベースが実際に何をしているかを確認し、適切なインデックスを追加し、N+1 クエリを排除して、必要なデータだけを選択します。
EXPLAIN ANALYZE は実行プランと実際のタイミングを表示します。大きなテーブル上のSeq Scanは典型的な警告信号です:
EXPLAIN ANALYZE
orders customer_id ;
インデックスは完全スキャンを高速ルックアップに変えます:
CREATE INDEX idx_orders_customer ON orders (customer_id);
-- Now: Index Scan using idx_orders_customer (cost=0.42..8.5 rows=120)
-- 1,000,000-row scan → ~120-row lookup
インデックスは書き込みにコストがかかります: すべての INSERT/UPDATE はインデックスも更新する必要があるため、フィルタ/結合/ソート対象の列にインデックスを付けます — すべての列ではなく。複合インデックス (customer_id, created_at) は WHERE customer_id = ? ORDER BY created_at を1つの構造で処理します。
N+1 問題 — リストに対して1つのクエリ、その後行ごとに1つ — は速度低下の主な原因です。eager loading、JOIN、またはバッチ処理 IN (...) で置き換えます:
-- N+1: 1 + 100 queries
SELECT * FROM orders; -- then per order: SELECT * FROM users WHERE id = ?
-- Fixed: one JOIN, only needed columns
SELECT o.id, o.total, u.name
FROM orders o JOIN users u ON u.id = o.user_id;
また必要な列だけを選択(SELECT * を避ける)して、LIMIT/keyset pagination でページネートすることで、数百万行を読み込まないようにします。
データベースは最も一般的なボトルネックです。プランを読むことで、推測する代わりになぜクエリが遅いのかがわかります。適切なインデックス、N+1 の削除、結果セットの削減は、ハードウェアをスケールしなくても、秒単位のクエリをミリ秒単位に変えることができます。