在开发过程中,难免需要对 sql 语句的问题排查,我们可以把程序执行中运行的 sql 语句记录到日志中。
甚至,还可以记录 sql 语句的执行时间,对执行时间过长的 sql 的语句增加预警等。
Laravel
框架提供的 sql 监听事件,只需要在 Provider 的 boot 方法里增加监听回调即可。
监听 sql 执行
这里以 Laravel 11 为例,参考官方文档:Listening for Query Events。
<?php
namespace App\Providers;
use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// ...
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
DB::listen(function (QueryExecuted $query) {
// 打印 sql 及执行耗时
Log::debug($query->toRawSql() . sprintf(' (%.2fms)', $query->time));
});
}
}
如果是在低版本的 Laravel 中,如在 Laravel 10 中,没有提供 $query->toRawSql()
,那么需要手动将 sql 和参数拼接出来打印。
/**
* Bootstrap any application services.
*/
public function boot(): void
{
DB::listen(function (QueryExecuted $query) {
// $query->sql;
// $query->bindings;
// $query->time;
$bindings = $query->bindings;
$sql = $query->sql;
foreach ($bindings as $replace) {
$value = is_numeric($replace) ? $replace : "'" . $replace . "'";
$sql = preg_replace('/\?/', strval($value), $sql, 1);
}
Log::debug($sql . " ({$query->time}ms)");
});
}
监视 sql 耗时
还可以监听 sql 执行时间,针对执行时间过长的 sql 的,发送通知等。
官方文档中也有介绍:Monitoring Cumulative Query Time。
/**
* Bootstrap any application services.
*/
public function boot(): void
{
// 对超过 500ms 的 sql 增加回调监听
DB::whenQueryingForLongerThan(500, function (Connection $connection, QueryExecuted $event) {
// Notify development team...
});
}
最后
这篇介绍了在 Laravel 中如何监听 sql 语句并打印 sql 到日志中,以及监视 sql 的执行耗时。这有助于开发者分析 sql 语句,并对慢 sql 做相应的优化,极大的提高了开发者的效率。