Laravel with() vs join()

閱讀時間約 9 分鐘
之前在執行某些專案的時候,常看到->with()這種寫法,因此一直都很好奇到底跟->join()寫法有什麼差別,哪一種寫法效能比較好呢?

資料情境:

假設現在情境是要撈出文章跟留言,目前共有2篇文章,每篇各有4萬筆留言,也就是留言table共有8萬筆資料:

程式碼:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Services\UserService;
use App\Models\Comment;
use App\Models\Article;
use DB;
use Exception;
class ArticleController extends Controller
{
    public function query(){
        /*
        for($i = 1 ; $i <= 20000 ; $i++){
            $comment = new Comment;
            $comment->article_id = 2;
            $comment->content = substr(md5(mt_rand()), 0, 50);
            $comment->save();
        }
        */
        try{
            DB::enableQueryLog();
            //---------------------------------------------------------------------------------
        
            $start = microtime(true);
            $query = Article::join('comment', 'comment.article_id', '=', 'article.id')
            ->select(
                'article.id',
                'article.title AS article_title',
                'comment.content AS comment_content'
            );
            $join_result = $query->get();
            $join_time = microtime(true) - $start;
            
    
            //---------------------------------------------------------------------------------
    
            $start = microtime(true);
            $query = Article::with([
                'comments' => function ($query) {
                    $query->select([
                        'article_id',
                        'content'
                    ]);
                }
            ]);
            $with_result = $query->get();
            $with_time = microtime(true) - $start;
            //---------------------------------------------------------------------------------
            
            $SQL = DB::getQueryLog();
    
    
            
            return response()->json([
                'status' => 'success',
                'SQL' => $SQL,
                'join_time' => $join_time,
                'join_result' => $join_result,
                'with_time' => $with_time,
                'with_result' => $with_result,
            ]);
        }
        catch (Exception $e) {
            return response()->json([
                'status' => 'fail',
                'message' => $e->getMessage()
            ], 500);
        }
    }
}

實驗結果:

  • 從結果可以看出,with這種寫法,共下了兩次sql,分別把文章跟留言都撈出來,再把資料mapping起來,with_result如下:
  • join寫法就不多解釋了,join_result如下:
  • join執行時間6.6s,with執行時間8.4s,單從執行時間上來看,join快一些。
  • 就資料面來看,with把資料整理得比較乾淨,大致上分為兩篇文章,下面的comments key就可以直接拿到該篇文章的所有留言,如果這個query api的目的是要抓出所有文章跟對應的留言的話,用with這種寫法比較簡潔,而且前端拿到資料後也幾乎不需要再整理過,可以說是好處多多。但如果是join寫法,可能還要group by 文章id,才能整理成with這種資料結構。

結論:

  • join與with寫法,回傳的資料結構不同,得視使用情境來選擇適合的寫法。
單就討論with跟join query寫法哪個比較快的話,從實驗數據來看,join會比較快,但是個人認為這個結論比較沒有意義,因為要看資料使用情境來決定要用哪種方式query,按上面所述,如果api目標是要回傳像with這種資料結構,在這邊說join比較快沒有意義,因為還少算了將join result資料整理的時間。
假設今天的情境是前端會自己by文章id去整理資料,對後端來說當然會選擇用join寫法囉,又或者是某些統計數據,需要join後再做group計算,這時候就很適合用join。
還有一種情況是,假設今天多了第三篇文章,但是還沒有任何留言,這時候用with也會把第三篇文章的資料抓出來,只不過留言資料是空的,如果不希望把沒有留言的文章也找出來,這時候選擇用join是很直覺的,如果想達到跟with一樣的結果(把沒有留言的文章也找出來),就可以用leftJoin。其實,除了with還有has, whereHas的用法,也可以達到leftJoin的效果。
無論如何,根據api使用情境來選擇,個人認為是比較明智的做法,而不是不管怎樣都一律用一樣的方式來query。
本筆記參考:
  1. https://learnku.com/laravel/t/30387
  2. https://laracasts.com/discuss/channels/laravel/laravel-join-vs-with-in-performance
  3. https://learnku.com/laravel/t/16565/lets-talk-about-the-comparison-between-laravel-with-and-join-welcome-to-explain
  4. https://segmentfault.com/q/1010000006114982
為什麼會看到廣告
21會員
161內容數
留言0
查看全部
發表第一個留言支持創作者!
Vic Lin的沙龍 的其他內容
本筆記會以簡單的例子說明,如何在Laravel中進行unit test 與 feature test。 phpunit.xml則是設定檔,可以設定哪些檔案要做測試,哪些要排除在外等等。 使用命令建立新的test case: 建立feature test: 建立unit test: 執行測試:
對於使用Laravel來講,可以直接用composer來安裝predis,可以說是相當方便: config/database.php: redis預設有16個資料庫,這邊是各個資料庫的連接設定。 要使用predis,要記得把env file中的REDIS_CLIENT改成predis。 .env:
Redis主要是運行在Linux系統環境中的,官方下載區找不到windows安裝程式,不過微軟有維護windows版本的,可以到github release page下載安裝。 直接下載msi來安裝: 測試是否安裝成功: 回傳PONG表示服務正常。 查看版本資訊: 列出所有key:
如上圖資料,想要group by g_id找到最大update_datetime的row:
MySQL中欄位數字相加可以很容易達成: 但假如其中一個欄位是null,最終的total也會是null,可能不符合預期需求。 解決方法,使用COALESCE將null轉為0:
若是用第一種callback方法,response json要包含連結跟unique code,這個連結是要給user查詢刪除狀態用的,從官方提供的範例PHP程式碼可得知。 Note: 別忘了圖1的「資料刪除回呼網址」記得填你的callback url。
本筆記會以簡單的例子說明,如何在Laravel中進行unit test 與 feature test。 phpunit.xml則是設定檔,可以設定哪些檔案要做測試,哪些要排除在外等等。 使用命令建立新的test case: 建立feature test: 建立unit test: 執行測試:
對於使用Laravel來講,可以直接用composer來安裝predis,可以說是相當方便: config/database.php: redis預設有16個資料庫,這邊是各個資料庫的連接設定。 要使用predis,要記得把env file中的REDIS_CLIENT改成predis。 .env:
Redis主要是運行在Linux系統環境中的,官方下載區找不到windows安裝程式,不過微軟有維護windows版本的,可以到github release page下載安裝。 直接下載msi來安裝: 測試是否安裝成功: 回傳PONG表示服務正常。 查看版本資訊: 列出所有key:
如上圖資料,想要group by g_id找到最大update_datetime的row:
MySQL中欄位數字相加可以很容易達成: 但假如其中一個欄位是null,最終的total也會是null,可能不符合預期需求。 解決方法,使用COALESCE將null轉為0:
若是用第一種callback方法,response json要包含連結跟unique code,這個連結是要給user查詢刪除狀態用的,從官方提供的範例PHP程式碼可得知。 Note: 別忘了圖1的「資料刪除回呼網址」記得填你的callback url。
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
Simple Storage Service (S3) 是 AWS 最常應用到的服務,只要是需要將檔案上傳到雲端的狀況都可以使用S3,本篇文章將介紹如何設定與使用AWS S3。
Thumbnail
在使用laravel中的Queue job的時候 如果希望job中斷還可以重新啟動這個時候就會需要用到Supervisor了 本篇文章為您帶來如何使用Supervisor執行Laravel的queue:work的教學
Thumbnail
有的時候,會希望在物件導向中對原生的Class新增功能的時候,大多我們都會寫一個新的class並繼承。 但是其實Laravel提供了一個不同的方式,讓我們可以在常用的Class上,直接新增想要的function,那就是macro。
Migration在 Laravel 中是一種用來管理資料庫結構變更的機制。它的主要目的是使開發者能夠在應用程序的不同環境中保持資料庫結構的一致性,並輕鬆地進行結構變更
Thumbnail
待業中後,發現時間變很多就開始東看看西看看,思考著要如何更深入理解Laravel框架的運用,而在Laravel框架中哪些部分是框架替我們做了哪些處理,推薦一個影片給大家一起學習理解。
Thumbnail
Ever wonder what will happen if you run into your “Clone” one day? See how Paul Rudd will react in Netflix's Living with Yourself to get his life back
  感覺很累,晚上開始又因為太過疲倦而心臟上方肌肉絞痛。   從覺得自己有很多是要做,但又同時很多事情做不來。   我想要看書,我希望今年看完一百本書。但是擺在更前面的是有時限的委託,這從的委託是我喜歡的劇情,但是希望人物不要失真光是看資料就夠花時間了。
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
Simple Storage Service (S3) 是 AWS 最常應用到的服務,只要是需要將檔案上傳到雲端的狀況都可以使用S3,本篇文章將介紹如何設定與使用AWS S3。
Thumbnail
在使用laravel中的Queue job的時候 如果希望job中斷還可以重新啟動這個時候就會需要用到Supervisor了 本篇文章為您帶來如何使用Supervisor執行Laravel的queue:work的教學
Thumbnail
有的時候,會希望在物件導向中對原生的Class新增功能的時候,大多我們都會寫一個新的class並繼承。 但是其實Laravel提供了一個不同的方式,讓我們可以在常用的Class上,直接新增想要的function,那就是macro。
Migration在 Laravel 中是一種用來管理資料庫結構變更的機制。它的主要目的是使開發者能夠在應用程序的不同環境中保持資料庫結構的一致性,並輕鬆地進行結構變更
Thumbnail
待業中後,發現時間變很多就開始東看看西看看,思考著要如何更深入理解Laravel框架的運用,而在Laravel框架中哪些部分是框架替我們做了哪些處理,推薦一個影片給大家一起學習理解。
Thumbnail
Ever wonder what will happen if you run into your “Clone” one day? See how Paul Rudd will react in Netflix's Living with Yourself to get his life back
  感覺很累,晚上開始又因為太過疲倦而心臟上方肌肉絞痛。   從覺得自己有很多是要做,但又同時很多事情做不來。   我想要看書,我希望今年看完一百本書。但是擺在更前面的是有時限的委託,這從的委託是我喜歡的劇情,但是希望人物不要失真光是看資料就夠花時間了。