Menu

023. N+1 问题捕杀神器 ——beyondcode/laravel-query-detector

N+1 问题捕杀神器 ——beyondcode/laravel-query-detector

N + 1 问题 是我们开发过程中必须避免的问题,通常情况下我们都会根据经验在必要的地方进行预加载,防止 N + 1 问题,有些时候则是根据查询日志或者 Laravel-Debugbar 等工具发现并及时修改掉 N + 1 问题。

开发总是会有疏忽的时候,通过经验或者日志工具都不够靠谱,有没有工具能及时的发现 N + 1 问题,并提示我们及时解决呢,今天我们要学习的 beyondcode/laravel-query-detector,就是这样的一个工具,我们一起安装一下。

安装

$ composer require beyondcode/laravel-query-detector --dev

注意我们使用了 --dev 参数,指定是开发环境的依赖。

file

我们这里安装的是 0.6.0,因为扩展包还在不断的更新当中,1.0 发布之前,版本可能发布的会很快,如果后续发布的版本有新的功能,我们会及时更新这篇文章。现在的版本已经可以很好的满足需求了。

将配置文件发布出来:

$ php artisan vendor:publish --provider=BeyondCode\\QueryDetector\\QueryDetectorServiceProvider

file

使用

先修改一下代码,制造一个 N + 1 问题,修改话题列表关于预加载的处理,在 Topic 模型中:

app/Models/Topic.php

.
.
.
    public function scopeWithOrder($query, $order)
    {
        // 不同的排序,使用不同的数据读取逻辑
        switch ($order) {
            case 'recent':
                $query = $this->recent();
                break;

            default:
                $query = $this->recentReplied();
                break;
        }
        return $query;
        // 预加载防止 N+1 问题
        // return $query->with('user', 'category');
    }
.
.
.

访问 LaraBBS 的话题列表 http://larabbs.test/topics

file

浏览器弹出了一个 Alert 框,提示我们 Topic 模型出现了 N + 1 问题,需要使用 with('user') 和 with('category')。

查看一下日志 tail -f storage/logs/laravel.log,也能看到关于 N + 1 问题的提示:

file

其他的提示方式

这里一下配置中所有的提示方式:

  • \BeyondCode\QueryDetector\Outputs\Alert::class —— 浏览器 Alert 提示;
  • \BeyondCode\QueryDetector\Outputs\Console::class —— 浏览器 console 提示;
  • \BeyondCode\QueryDetector\Outputs\Clockwork::class —— 浏览器 clockwork插件提示,该扩展包的安装建 课程
  • \BeyondCode\QueryDetector\Outputs\Debugbar::class —— Laravel-Debugbar 提示;
  • \BeyondCode\QueryDetector\Outputs\Json::class —— json 响应提示,由于 LaraBBS 中使用了 Dingo 扩展包完成接口数据的返回,该配置对现有接口没有作用。任何继承了 Illuminate\Http\JsonResponse 的响应都会自动添加提示;
  • \BeyondCode\QueryDetector\Outputs\Log::class —— 日志提示;

提示在哪里是可以配置的,尝试修改一下配置:

config/querydetector.php

.
.
.
    'output' => [
        \BeyondCode\QueryDetector\Outputs\Alert::class,
        \BeyondCode\QueryDetector\Outputs\Log::class,
        \BeyondCode\QueryDetector\Outputs\Console::class,
        \BeyondCode\QueryDetector\Outputs\Clockwork::class,
        \BeyondCode\QueryDetector\Outputs\Debugbar::class,
    ]
.
.
.

查看 clockwork 中的日志:
file

查看 debugbar 中的数据查询:
file

查看浏览器 console 中的输出:
file

白名单功能

扩展包还提供了白名单的功能,也就当某个模型的的某个关系出现了 N + 1问题的时候,不进行报错。相当于手动取消了对某个模型预加载的监控,或许你会在某个特殊的场合遇到这样的白名单使用场景,我们只是来测试一下功能。调整一下白名单的配置:

config/querydetector.php

.
.
.
    'except' => [
        App\Models\Topic::class => [
            App\Models\Category::class,
            'category',
        ]
    ],
.
.
.

设置为不出了 Topic 模型关于 Category 预加载的检测,再次访问话题列表页面:

file

已经没有了关于 with('category') 的提示。

代码版本控制

可以根据需求调整相关的输出位置,我们将代码还原为在页面中进行 alert 提示以及在日志中提示。

config/querydetector.php

.
.
.
    'except' => [
    ],
    'output' => [
        \BeyondCode\QueryDetector\Outputs\Alert::class,
        \BeyondCode\QueryDetector\Outputs\Log::class,
    ]
.
.
.

提交代码:

$ git add -A
$ git commit -m 'beyondcode/laravel-query-detector'

本文章首发在 Laravel China 社区
上一篇 下一篇
讨论数量: 0
发起讨论


暂无话题~
刻意练习,每日精进。
36
点赞
1823
浏览
0
讨论