0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

laravel6.0でのsubQueryの書き方(+subQuery vs EagerLoadingについて)

Posted at

# はじめに
 laravel6.0が出て数日たちましたね。
 今までsubQueryどころかEagerLoadingすらも面倒だからいいやとサボっていた人間なので、
 この機会に少しまとめておきたいと思います。

 laravel6.0でのsubQuery

 今usersとbooksがあるとして

  function ($query) {
          $query->select("name")->from("books")->whereColumn("user_id", "users.id")
              ->limit(1);
  }

 これをaddSelectや、orderByに入れるだけです。

 $users = User::addSelect(["book_name" => function ($query) {
           $query->select("name")->from("books")->whereColumn("user_id", "users.id")
               ->limit(1);
       }])->get();

 foreach ($users as $user) {
           $name = $user->book_name;
       }

 こんな感じです。

# 何もしない vs EagerLoading vs subQuery

user_book_er.png
 

 controllerを作ってそこにアクセスして比較していきます。

SampleController.php

  class SampleController extends Controller
    {

    public function index()
    {
        $start = microtime(true);
        $memory = memory_get_usage();

        $this->getBooks();

        $result = [
            "time" => microtime(true) - $start,
            "memory" => (memory_get_peak_usage() - $memory) / (1024 * 1024)
        ];

        dump($result);
    }

    public function getBooks()
    {

        //optionalはuserに対応するbookが必ず存在するとは限らないためつけてます。       

        //通常
        $users = User::all();
        foreach ($users as $user) {
            $name = optional($user->books->first())->name;
        }

        //EagerLoading
        $users = User::with("books")->get();
        foreach ($users as $user) {
            //リレーションメソッドにしてしまうとeagerloadingの効果が失われてしまうので気を付けて
            $name = optional($user->books->first())->name;
        }

        
        //subQuery
        //addSelectによりusersのすべてと、book_nameが選択されている状態
        $users = User::addSelect(["book_name" => function ($query) {
            $query->select("name")->from("books")->whereColumn("user_id", "users.id")
                ->limit(1);
        }])->get();

        foreach ($users as $user) {
            $name = $user->book_name;
            
        }
    }
}

 user 1000件 book 1000件の場合

method time memory
通常 2.1359429359436 4.7769012451172
EagerLoading 0.242516040802 4.222671508789
subQuery 0.46214890480042 3.937858581543

 user 3000件 book 3000件の場合

method time memory
通常 8.952919960022 13.542144775391
EagerLoading 0.79955101013184 11.902877807617
subQuery 3.0595591068268 10.085777282715

 user 5000件 book 5000件の場合

method time memory
通常 19.71000289917 28.348297119141
EagerLoading 1.9218430519104 25.727615356445
subQuery 6.256618976593 16.407073974609

 user 10000件 book 10000件の場合
 通常は60秒を超えてtimeoutでした。

method time memory
通常
EagerLoading 3.9436728954315 50.53173828125
subQuery 24.066353082657 31.92147064209

# まとめ
  上の結果だけ見るとEagerLoading一択みたいに見えるんですけど、
  書き方や計測方法が悪いだけなんですかね・・・?
  memory的にはやっぱりsubQueryがいい感じなんだけども・・・
  おそらくどこか間違っていると思うので詳しい方いたら指摘していただければ助かります!

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?