快捷打印 Laravel 中的数据库查询(SQL)语句
5天前 ⋅ 375 ⋅ 11 ⋅ 11
闲话少叙,直接入题。首先,为什么要打印 Laravel 中 Query Builder 构建的 SQL 语句?
答案很简单,就是我要知道到底执行了什么 SQL 语句,这样我就能合适地写 Query Builder、在适合用『热加载』的场景不会误用『懒加载』。
热加载#
$user = User::where('name', 'Eric')->with('articles')->first();
上面就是热加载的例子――获取第一个名为『Eric』的用户信息同时,把他的文章也全都取到。
这样的使用场景下,Query Builder 只使用了类似下面的两条 SQL 语句。
select * from users where name = 'Eric' limit 1;
select * from articles where user_id in (22);
就是说当你用 $user->articles
遍历用户文章时,不会再请求数据库了。
懒加载#
懒加载和热加载是相对的。下面就是懒加载的例子。
$user = User::where('name', 'Eric')->first();
// 在 Blade 模版里遍历打印出用户文章
@\foreach($user->posts as $post)
// ...
@endforeach
这种用法能达到效果,但是效率会变低――每次遍历、处理的一篇文章信息,都是向数据库执行一次 SQL 得到的。
如果用户有 N 篇文章,就要执行 N 次 SQL 查询,再加上之前请求用户信息的 1 次 SQL,这就是所谓的『N+1』问题。
明明能 2 次完成的事,就不要再花 N+1 次了。
打印 SQL#
像上面的状况,如果我们知道底层是怎样执行 SQL 语句的,也许就不会发生了。这就为我们找出了一个有必要打印 SQL 语句来看的理由。
既然文章题目是『快捷打印 SQL』,自然配置起来也很简单。配置到最后的结果的是:
当你的 APP_ENV
设置为 local
、请求 URL 后面紧跟 ?sql-debug=1
时,就会打印出请求处理逻辑中涉及到的所有数据库查询语句。
配置#
AppServiceProvider
的 boot
方法内写入
use DB;
use Event;
if ( env('APP_ENV') === 'local' ) {
DB::connection()->enableQueryLog();
Event::listen('kernel.handled', function ( $request, $response ) {
if ( $request->has('sql-debug') ) {
$queries = DB::getQueryLog();
if (!empty($queries)) {
foreach ($queries as &$query) {
$query['full_query'] = vsprintf(str_replace('?', '%s', $query['query']), $query['bindings']);
}
}
dd($queries);
}
});
}
注意:路由有两种形式——基于闭包(Closure)和基于控制器动作(Controller Action)的。上面的配置只对基于控制器动作的路由有效。