Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPerKaigi 2022 【Laravel】 サクッとN + 1問題を見つけて倒しチャオ!

y-tsuzaki
April 11, 2022

PHPerKaigi 2022 【Laravel】 サクッとN + 1問題を見つけて倒しチャオ!

N + 1問題とは、ループ処理の中で都度SQLを実行してしまうことで必要以上にSQLが発行されてしまい処理が遅くなってしまう問題です。
N + 1問題が存在していても、ユーザーに影響のない程度の処理時間なら改修する必要はありません。
しかしながら、データ量が増えたりページへのアクセスが増えることで後から問題になってしまうこともあります。
今回は、そんなN + 1問題をサクッと検出して、問題が発生する前にN + 1問題を撲滅する方法をご紹介します。

https://fortee.jp/phperkaigi-2022/proposal/4307d420-7ef0-4b69-b3f7-005b72bf87b0

y-tsuzaki

April 11, 2022
Tweet

More Decks by y-tsuzaki

Other Decks in Programming

Transcript

  1. Copyright© M&Aクラウド 10 EloquentのリレーションによるN+1問題 Eager(積極的)ロードでN+1問題を直します すべて「本」に紐づく「著者」をとってきたい場合 $books = Book::all(); foreach

    ($books as $book) { echo $book->author->name ; } 何も工夫せず書くと すべての本取得に1クエリ実行 1つの本に紐づく著者の取得に1クエリ実行。本が25個ある場合、25+1回クエリが実行される。 with句を使えば2クエリで済むようになる。 $books = Book::with('author')->get(); foreach ($books as $book) { echo $book->author->name; }
  2. Copyright© M&Aクラウド 14 EloquentのリレーションによるN+1問題 preventLazyLoadingはLaravel 8から追加された機能です。 AppServiceProviderのboot()で呼び出しを追加します。 use Illuminate¥Database¥Eloquent¥Model; public

    function boot() { Model::preventLazyLoading(! $this->app->isProduction()); } このように設定することで実行時に例外を投げるようになるので、開発中にwithのつけ忘れに気づくことができます。
  3. Copyright© M&Aクラウド 17 Eloquent外でのN+1問題 - そもそもEloquent使ってないケース - 直接PHPでSQL書いてる - クエリビルダーを使っている

    - など - ドメイン層など別のレイヤーのループ処理でDBアクセスを行っているケース - など
  4. Copyright© M&Aクラウド 21 Eloquent外でのN+1問題 サンプルコード abstract class MyTestCase extends TestCase

    { protected int $queryCount = 0; protected function setUp(): void { parent::setUp(); DB::listen(function () { $this->queryCount++; }); } protected function tearDown(): void { if ($this->queryCount > 50) { Log::warning("[WARNING] TOO MANY QUERY! query count: " . $this->queryCount . " " . get_class($this) . "#" . $this- >getName()); } parent::tearDown(); } }