はじめに
DB利用した実装している際に注意しながらも見落としてしまうN+1問題ですが、自動的に検出してくれるツールがあるのでご紹介します。
Laravel N+1 Query Detector
インストール
composer経由でインストール出来ます。
composer require beyondcode/laravel-query-detector --dev
設定
そのままでもすぐに使用できますが、折角なので設定変更しましょう
/vendor/beyondcode/laravel-query-detector/config/config.php
から
/config/querydetector.php
へ、
configファイルが生成されます。
php artisan vendor:publish --provider=BeyondCode\\QueryDetector\\QueryDetectorServiceProvider
通知方法の追加
デフォルトではアラートとログファイルに検知内容が表示されますが、今回はコンソールにも表示させたいと思います。
設定ファイルの
output
の箇所に追記します。
1 2 3 4 5 6 7 8 | 'output' => [ // 画面上でアラートを検知内容を表示 \BeyondCode\QueryDetector\Outputs\Alert::class, // ログファイルに検知内容を表示 \BeyondCode\QueryDetector\Outputs\Log::class, // コンソール上に検知内容を表示 \BeyondCode\QueryDetector\Outputs\Console::class, // 追記 ] |
テスト
N+1を発生させて、検知させてみたいと思います。
適当なコントローラーとモデルを作成します。
1 2 3 4 5 6 | class Member extends Model { public function comments() { return $this->hasMany(Comment::class, 'member', 'id'); } } |
1 2 3 4 5 6 | class Comment extends Model { public function members() { return $this->belongsTo(Member::class, 'member', 'id'); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class Member extends Controller { public function index() { // Memberモデルの取得 $members = \App\Models\Member::all(); foreach ($members as $member) { // リレーションでCommentモデルを取得 // Memberモデルの数だけクエリが作成される(N+1) $comments = $member->comments; } return view('member.index',compact( 'members', )); } } |
検知結果
以下の様に検知出来ています
画面上アラート
コンソール
ログファイル
ちなみに
configファイルに以下の記述があります。
環境変数にQUERY_DETECTOR_ENABLEDを定義しなければ、環境変数APP_DEBUGを見て、検知内容の表示/非表示を分けている様です。
1 2 3 4 5 | /* * Enable or disable the query detection. * If this is set to "null", the app.debug config value will be used. */ 'enabled' => env('QUERY_DETECTOR_ENABLED', null), |
さいごに
N+1を見落とす確率が大分減ると思うので、こうしたツールは積極的に利用したいですね。