「SQLが遅いけど、どこを直せばいいか分からない」と悩んでいませんか?
この記事では、SQLチューニングの基本を解説します。
パフォーマンス問題の特定
EXPLAIN で実行計画を確認
sql
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
重要な指標
| 指標 | 意味 | 目安 |
|---|---|---|
| type | アクセスタイプ | ALL以外 |
| rows | 走査行数 | 少ないほど良い |
| Extra | 追加情報 | Using filesortは注意 |
type の種類(良い順)
- const: 主キー/ユニーク検索
2. ref: インデックス検索
3. range: 範囲検索
4. index: インデックスフルスキャン
5. ALL: テーブルフルスキャン(避けたい)
インデックス設計
基本原則
sql
-- 単一カラムインデックス
CREATE INDEX idx_users_email ON users(email);
-- 複合インデックス
CREATE INDEX idx_users_status_created ON users(status, created_at);
インデックスを張るべきカラム
| 条件 | 優先度 |
|---|---|
| WHERE句で頻繁に使う | ★★★ |
| JOINのキー | ★★★ |
| ORDER BYで使う | ★★☆ |
| カーディナリティが高い | ★★☆ |
複合インデックスの順序
sql
-- WHERE status = ? AND created_at > ? の場合
-- 左から順に使われる
CREATE INDEX idx_status_created ON users(status, created_at); -- OK
CREATE INDEX idx_created_status ON users(created_at, status); -- 効果薄
クエリ最適化
1. SELECT * を避ける
sql
-- NG
SELECT * FROM users;
-- OK
SELECT id, name, email FROM users;
2. サブクエリをJOINに
sql
-- NG(遅い)
SELECT * FROM orders
WHERE user_id IN (SELECT id FROM users WHERE status = 'active');
-- OK(速い)
SELECT o.* FROM orders o
JOIN users u ON o.user_id = u.id
WHERE u.status = 'active';
3. OR を UNION に
sql
-- NG
SELECT * FROM users WHERE email = '[email protected]' OR name = 'test';
-- OK
SELECT * FROM users WHERE email = '[email protected]'
UNION
SELECT * FROM users WHERE name = 'test';
4. OFFSET を避ける
sql
-- NG(OFFSET大きいと遅い)
SELECT * FROM posts ORDER BY id LIMIT 20 OFFSET 10000;
-- OK(カーソルベース)
SELECT * FROM posts WHERE id > 10000 ORDER BY id LIMIT 20;
5. LIKE の前方一致
sql
-- インデックス使える
SELECT * FROM users WHERE name LIKE 'tanaka%';
-- インデックス使えない
SELECT * FROM users WHERE name LIKE '%tanaka%';
N+1問題
問題のあるコード
sql
-- 1回
SELECT * FROM users;
-- N回
SELECT * FROM posts WHERE user_id = 1;
SELECT * FROM posts WHERE user_id = 2;
SELECT * FROM posts WHERE user_id = 3;
...
解決策:JOINまたはIN
sql
-- JOIN
SELECT u., p. FROM users u
LEFT JOIN posts p ON u.id = p.user_id;
-- IN
SELECT * FROM posts WHERE user_id IN (1, 2, 3, ...);
まとめ
SQLチューニングのポイント:
1. EXPLAINで実行計画を確認
2. インデックスを適切に設計
3. N+1問題を解消
4. SELECT \* を避ける
関連記事
Tech Creator Hub
より詳しい情報は、Tech Creator Hubをご覧ください。