データベースクエリの最適化
N+1クエリを特定し、インデックスを追加してクエリ数を減らします
「データベースクエリの最適化」はCoddyKit上の無料PHP Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPHP Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 PHP Academyコースには全4レッスンが含まれています。
遅いクエリの特定
MySQLのスロークエリログを有効にし、しきい値を設定します。想定より時間のかかっているクエリを確認します。
# my.cnf:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 0.5 # log queries over 500msEXPLAIN/EXPLAIN ANALYZE
EXPLAINを使用して、MySQLがクエリをどのように実行するか、インデックスが使用されているかを確認します。
-- Run in MySQL:
EXPLAIN SELECT * FROM orders WHERE user_id = 42 AND status = "pending";
-- Look for: type=ALL (full scan), key=NULL (no index used)インデックスの追加
インデックスにより、条件指定や並べ替えの対象となる列の読み取りが大幅に高速化されます。
-- Add composite index for the query above:
ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);
// In Laravel migration:
$table->index(["user_id", "status"]);N+1クエリ問題
N+1問題では、一覧を取得するために1回クエリを実行し、リレーションのために項目ごとに1回ずつクエリを実行します。Eager Loadingで解決します。
<?php
// BAD: 1 + N queries
$posts = Post::all();
foreach ($posts as $post) echo $post->author->name;
// GOOD: 2 queries
$posts = Post::with("author")->get();
foreach ($posts as $post) echo $post->author->name;必要な列だけを選択する
SELECT *は避け、必要な列だけを取得してメモリ使用量とネットワーク転送量を削減します。
<?php
// Bad:
$users = User::all();
// Good:
$users = User::select("id", "name", "email")->get();大規模データセットのチャンク処理
大きな結果セットはチャンク単位で処理し、メモリ不足を防ぎます。
<?php
User::chunk(500, function ($users) {
foreach ($users as $user) {
// process each user
}
});
// Or lazy loading (PHP generator):
User::lazy()->each(fn($user) => processUser($user));クエリキャッシュ
頻繁には変わらない高コストの集計やレポートをキャッシュします。
<?php
$revenue = Cache::remember("monthly-revenue", 3600, function () {
return Order::whereMonth("created_at", now()->month)->sum("total");
});ループ内のクエリを避ける
foreachループ内でクエリを実行してはいけません。先にIDを集めてから、1回のクエリで取得します。
<?php
// Collect all product IDs:
$ids = array_column($cartItems, "product_id");
// One query:
$products = Product::whereIn("id", $ids)->get()->keyBy("id");
foreach ($cartItems as $item) {
$product = $products[$item["product_id"]];
}データベース接続プーリング
PHP-FPMはワーカーごとに新しいPDO接続を作成します。PgBouncerやProxySQLを使用すると接続をプールでき、接続処理のオーバーヘッドによってDBに過大な負荷がかかるのを防げます。
カバリングインデックス
カバリングインデックスには、クエリの実行に必要なすべての列が含まれます。MySQLはメインテーブルの行にアクセスせず、インデックスだけでクエリに回答できます。
まとめ
スロークエリログを有効にします。EXPLAINを使用して不足しているインデックスを見つけます。リレーションをEager Loadingします。必要な列だけを選択します。大規模なデータセットはチャンク処理します。高コストの集計をキャッシュします。ループ内のクエリを避けます。
理解度チェック
N+1クエリ問題とは何ですか。
よくある質問
「データベースクエリの最適化」レッスンは無料ですか?
はい。「データベースクエリの最適化」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、PHP Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 PHP Academyコースには全4レッスンが含まれています。
「データベースクエリの最適化」で何を学びますか?
N+1クエリを特定し、インデックスを追加してクエリ数を減らします ブラウザで直接実行するハンズオンコードでPHP Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
PHP Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのPHP Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「データベースクエリの最適化」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このPHP Academyレッスンでコードを書いて実行できますか?
はい。すべてのPHP Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。