Laravel 如何查看实际执行的 SQL 查询

DB::enableQueryLog() + DB::getQueryLog() 查看查询日志;DB::listen() 实时监听每条 SQL 及耗时;dd($query->toSql()) 看单条构造器 SQL。附 Telescope 与 APM 方案。

最佳实践
数据整理与查询插画

一句话回答:三种方式按需选:调试用 DB::enableQueryLog() 开启查询日志,跑完操作后 dd(DB::getQueryLog()) 打印该连接启用日志后记录的查询;实时监控用 DB::listen(fn($q) => Log::debug($q->sql));只想看某条正在构造的查询用 $query->toSql()(不执行)。

版本范围:以下 Laravel 示例按 12.x 官方文档核对;其他版本请检查对应 API 与配置差异。

方法一:查询日志(调试首选)

DB::enableQueryLog();          // 默认关闭,需显式开启

$users = User::where('active', 1)->get();   // 你的业务代码

dd(DB::getQueryLog());
// 输出数组:每条含 query(带占位符 SQL)、bindings(绑定值)、time(毫秒)

注意:getQueryLog() 里的 query 是带 ? 占位符的,真实参数在 bindings 里。数据库通常分别接收预处理语句与绑定值,并非一定有一条拼好的 SQL 字符串;调试展开仅作可读表示,不应拿去重新执行。

方法二:DB::listen 实时监听

在 AppServiceProvider::boot() 或临时代码里:

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

if (app()->environment('local')) {
    DB::listen(function ($query) {
        Log::debug($query->sql, [
            'time_ms' => $query->time,
            // 不默认记录 bindings,避免密码、Token 与个人数据入日志
        ]);
    });
}

Laravel 发出 QueryExecuted 事件时触发,可用于观察通过 Laravel 数据库层执行的查询;直接绕过该层的驱动调用不会因此自动可见。重复查询是 N+1 的线索,仍需结合调用位置判断。

方法三:单条查询看 SQL

$query = User::where('active', 1)->orderBy('created_at');
dump($query->toSql());          // select * from `users` where `active` = ? ...
dump($query->getBindings());    // [1]

// 支持此方法的 Laravel 版本可展开参数,仅限本地脱敏调试
User::where('active', 1)->dumpRawSql();

toSql() 不执行查询,只返回构造好的 SQL 字符串。

方法四:Laravel Telescope / Debugbar

  • Laravel Telescope(官方):按官方流程安装包、发布资源、运行所需迁移并配置 watcher/filter 后,Queries 面板可查看被记录的查询及耗时。还需配置访问授权、保留/清理策略和敏感参数处理,不能直接向公网开放
  • laravel-debugbar(第三方):页面底部调试条实时显示本请求 SQL,开发环境神器

生产环境别开 Telescope 全量记录(有性能开销),用采样或换 APM。

常见问题(FAQ)

Q:getQueryLog() 返回空数组?

A:两个原因:enableQueryLog() 在执行查询之后才被调用(顺序反了);或者查询走的是另一个数据库连接——query log 是按连接分开的,对对应连接 DB::connection('xxx')->enableQueryLog()。

Q:生产环境能开着 query log 吗?

A:不建议。查询日志把每条 SQL 存在内存里,长进程(Octane/队列 worker)会持续累积撑爆内存。生产排查慢查询用 MySQL slow log 或 APM。

Q:绑定的参数和 SQL 怎么拼成完整可执行的语句?

A:支持该 API 的版本可在 DB::listen 的 QueryExecuted 事件或 Builder 上用 toRawSql();getQueryLog() 返回的是数组,数组条目没有这个方法。不要用 vsprintf 或简单替换问号自行拼接,容易破坏引用/转义,也可能泄露敏感参数。

核查依据

本文依据官方文档核对,示例未在实际业务环境运行;上线前请按部署版本、权限与数据范围验证。


延伸阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台