| この記事の要点 |
|
Laravel の Eloquent やクエリビルダが実際にどんな SQL を発行しているかを確認する方法を、目的別にまとめます。N+1 問題の発見や、意図しない条件で検索されていないかの確認に使えます。
目的別の方法の選び方
| やりたいこと | 方法 | 実行されるか |
|---|---|---|
| 特定の処理で発行された SQL を一覧で見る | DB::enableQueryLog / getQueryLog | 実行される |
| 1 つのクエリの SQL 文を確認する | toSql / toRawSql / dumpRawSql | 実行されない |
| すべての SQL をログファイルに残す | DB::listen | 実行される |
| ブラウザ上で常に確認する | Laravel Debugbar / Telescope | 実行される |
方法 1: DB::enableQueryLog と getQueryLog
クエリログの収集を有効にしてから処理を実行し、最後に収集した結果を取り出します。
use Illuminate\Support\Facades\DB;
DB::enableQueryLog();
// ここで SQL を実行する処理
$items = TestTable::orderBy('col1', 'desc')->paginate(9);
dd(DB::getQueryLog());
上記の実装をすることで、SQL を走らせると画面に以下のような結果が出力されます。
array:1 [▼
0 => array:3 [▼
"query" => "select * from `test_table` order by `col1` desc limit 9 offset 0"
"bindings" => []
"time" => 2.22
]
]
query は SQL 文(プレースホルダは ? のまま)、bindings はプレースホルダに入る値、time は実行時間(ミリ秒)です。古い記事では use DB; と書かれていることがありますが、現在は use Illuminate\Support\Facades\DB; と完全なクラス名で書くのが確実です。
クエリログはメモリに溜まり続けるため、バッチ処理などで大量の SQL を流す場合は有効にしたままにしないでください。必要なら DB::disableQueryLog() や DB::flushQueryLog() で止める・消すことができます。別の DB 接続を使っている場合は DB::connection('mysql2')->enableQueryLog() のように接続ごとに有効にします。
方法 2: toSql / toRawSql で SQL 文だけ見る
クエリを実行せずに、組み立てられた SQL を確認できます。
$query = User::where('status', 'active')->where('age', '>=', 20);
// プレースホルダのままの SQL
echo $query->toSql();
// select * from `users` where `status` = ? and `age` >= ?
// バインド値を埋め込んだ SQL(Laravel 10.15 以降)
echo $query->toRawSql();
// select * from `users` where `status` = 'active' and `age` >= 20
// 出力して続行 / 出力して停止
$query->dumpRawSql();
$query->ddRawSql();
toRawSql() の出力はそのままデータベースクライアントに貼り付けて実行できるので、EXPLAIN で実行計画を調べるときに便利です。ただし、get() や first() を呼ぶ前のクエリビルダに対して使う必要があります。リレーションの Eager Loading(with)で追加発行される SQL は含まれないため、それらも見たい場合は方法 1 か方法 3 を使います。
方法 3: DB::listen ですべての SQL をログに出す
アプリ全体で発行された SQL を storage/logs/laravel.log に記録するには、app/Providers/AppServiceProvider.php の boot() にリスナーを登録します。
use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
public function boot(): void
{
if (config('app.debug')) {
DB::listen(function (QueryExecuted $query) {
Log::debug('SQL', [
'sql' => $query->sql,
'bindings' => $query->bindings,
'time_ms' => $query->time,
]);
});
}
}
この例では APP_DEBUG=true のときだけ記録します。専用のログチャンネル(config/logging.php に sql チャンネルを追加し、Log::channel('sql') で書く)を作ると、通常のログと混ざらず見やすくなります。
遅いクエリだけを検出したい場合は、DB::whenQueryingForLongerThan() を使うと、1 リクエスト内のクエリ合計時間がしきい値を超えたときだけ処理を実行できます。
方法 4: 開発用パッケージで画面に表示する
- Laravel Debugbar(barryvdh/laravel-debugbar): ページ下部にツールバーを出し、そのリクエストで実行された SQL・件数・時間・重複クエリを表示する
- Laravel Telescope(公式): リクエスト・クエリ・ジョブ・例外などを記録し、専用画面で後から閲覧できる。遅いクエリの強調表示もある
どちらも開発環境専用として composer require --dev で入れるのが基本です。本番環境で有効のままにすると、SQL やリクエスト内容が外部から見える危険があります。
よくある落とし穴
- getQueryLog が空になる: enableQueryLog を SQL 実行より後に呼んでいる、または別の接続で実行されている
- dd() の後の処理が動かない: dd は処理を止める。続行したいなら
dump()を使う - 本番でログが肥大化する: DB::listen を無条件に登録すると、全リクエストの SQL が記録されディスクを圧迫する。パスワードや個人情報がバインド値としてログに残る点にも注意
- toRawSql の値は参考用: 埋め込み表示はあくまで確認用。実際の実行はプリペアドステートメントで行われている
確認方法
方法 3 を設定した場合は、ページを 1 回開いてから storage/logs/laravel.log を確認します。同じ形の SQL が何十回も並んでいれば N+1 問題の可能性が高く、with() による Eager Loading で回数を減らせます。修正前後でログに出る SQL の件数を比べると、効果を確認できます。
関連
- PHPログ出力完全ガイド(error_log/Monolog/PSR-3/Laravel/logrotate)
- PHP var_dump をログ出力する完全ガイド
- PHP エラーログ出力 (error_log / Monolog / Laravel Log) 完全ガイド
- Django で SQL ログを出力する方法|django.db.backends と N+1 の発見
子ページはありません
- インストールと設定
- クイックスタート & チュートリアル(初心者向け)
- クイックスタート & チュートリアル(中級者向け)
- ルーティング
- Bladeテンプレート(ビュー/レイアウト)
- コントローラー
- マイグレーションとテーブル定義
- データベースの設定
- Eloquentモデル (ORM)
- SQLとクエリビルダー
- バリデーション
- .envファイルの設定値へのアクセス
- 動作環境による分岐処理
- configフォルダ配下の設定値へのアクセス
- assetヘルパーを利用したpublicフォルダへのアクセス
- storageフォルダへのアクセス
- アプリケーション名の変更
- メンテナンス
- ログイン画面(認証システム)の作成
- ログインの必須化
- ログインユーザー情報の取得
- ルートの認証化
- 本番サーバーへのデプロイ方法
- 多言語化
- csrf_field
- ファイルのダウンロード
- CSVのアップロードおよび読み込み(maatwebsite/excel)
- ページタイトルの設定
- コマンド一覧
- エラー一覧
- SQLの実行ログ出力方法
- キャッシュのクリア
- Selectの結果の最初もしくは最後に任意の値を追加する方法
- ajaxでPOST通信する際の注意点
- ソーシャルログインの実装
- セッション情報の確認
- ログイン、ユーザー登録、パスワードリセット後のリダイレクト先の変更方法
- redirectやreturn viewにメッセージを付与する方法
- クッキー(cookie)の設定と取得
- クラスの再読み込み
- csrfの有効時間を変更する方法
- ViewComposerを用いてviewに共通の値を付与する方法
- View::shareを用いて共通の値を各ビューに渡す方法
- ミドルウェアを用いた処理の共通化
- Middleware内でAuth::check()などを使用する方法
- Controller以外でリダイレクトする方法
- セッションの値の取得/保存/更新/削除
- $requestの値を変更する方法
- 常時SSL化
- ページング(ページネーション)をする方法
- vue.jsとの連携
- Vue.jsと連携するSPA実行環境構築
- .envの値をvue.jsで参照する方法
- vue.jsを本番環境にリリースする方法
- could not find driver(Windows, MySQL編)
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- プロジェクトをTomcatプロジェクトとして認識させる方法 2026-10-07 22:32:50
- MySQLの1366 Incorrect string value|Laravelの文字コード・絵文字エラー 2026-10-07 21:54:03
- curlの証明書ホスト名不一致|旧エラー51・現行60の確認と対処 2026-10-07 21:54:03
- LaravelのMassAssignmentException|fillableの原因と安全な対処 2026-10-07 21:54:03
- Eclipse で Tomcat の起動ログがコンソールに出ない時の確認手順 2026-10-07 21:54:02
- MySQLにおける中央値(Median)の導き方(バージョン8未満) 2026-10-07 13:49:45
- getInputForward 2026-10-07 13:41:15
- JSONから配列に変換 2026-10-07 13:41:15
- ビューから値をモデルに格納しコントローラーで受け取る方法 2026-10-07 13:23:41
- Laravelのテーブル作成と定義変更|マイグレーション・up/down・注意点 2026-10-07 13:23:41
- NumPy 配列に要素を追加する方法 (append / concatenate) 2026-10-07 13:23:41
- MariaDB・MySQLで現在日時を取得する方法|NOW・タイムゾーン・保存型 2026-10-07 13:13:36
- 【django】テンプレートで定数を使用する方法 2026-10-07 13:10:15
- Spring BootにおけるApplication.propertiesの環境依存設定の分割方法 2026-10-07 12:09:35
- Not supported for DML operations【Springエラー】 2026-10-07 11:09:38