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
為什麼會看到廣告
avatar-img
21會員
161內容數
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
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
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
CodeIgniter 3 和 Laravel 是兩種不同的 PHP 框架,各有其特點和適用場景。CodeIgniter 3 是一個輕量級框架,Laravel 是一個功能強大的現代 PHP 框架,同樣都有Models的它們有什麼樣的差別呢?
Thumbnail
※ 為什麼需要 Subquery? 當⼀個任務需要多個 Query 完成任務,可以使⽤ Subquery 把多個 Query 合併成⼀個 Query。 當我們在進行SQL查詢時,每次查詢都需要在Web Server和資料庫之間來回傳遞資料。這個過程會產生網路延遲,特別是當兩者之間的物理距離較遠時
Thumbnail
※ 何時該使用 JOIN? JOIN 使用的時機是:當你需要同時查詢一張以上的資料表的時候。 ※ SQL有哪些TABLE JOIN的方式? INNER JOIN LEFT JOIN RIGHT JOIN SELF JOIN ※ 使用 JOIN 的時候,我們需要考慮到: 我要使用哪一種
Thumbnail
在進行SQL查詢邏輯更改時,需要適當地使用SubQuery和join來達到新的排序需求。本文將介紹原本的撈取邏輯、需求以及如何使用SubQuery來解決新的排序需求。
Thumbnail
有的時候,會希望在物件導向中對原生的Class新增功能的時候,大多我們都會寫一個新的class並繼承。 但是其實Laravel提供了一個不同的方式,讓我們可以在常用的Class上,直接新增想要的function,那就是macro。
Thumbnail
延伸 MATCHES「|」的 OR 字元應用,我們還可以讓它跟工作表內的範圍做連動,做出更彈性的 QUERY。一起來看看怎麼做吧!
Thumbnail
在用 QUERY 查詢資料時,你曾遇過在 WHERE 寫很多個 OR 的狀況嗎?有個更簡單好用的寫法推薦給你,來瞧瞧!
Thumbnail
本文將介紹 SQL 中的連接(JOIN),連接(JOIN)是用於結合來自兩個或多個資料表的相關數據,建議讀過我之前發佈的幾篇"SQL學習筆記"之後再來看這篇。
Thumbnail
題目敘述 題目會給我們兩張資料表,第一張是Sales,第二張是Product。 第一張是Sales表格,裡面分別有sale_id、 product_id、year、quantity、price等欄位。其中(sale_id、 product_id)做為複合主鍵Primary key Table:
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
CodeIgniter 3 和 Laravel 是兩種不同的 PHP 框架,各有其特點和適用場景。CodeIgniter 3 是一個輕量級框架,Laravel 是一個功能強大的現代 PHP 框架,同樣都有Models的它們有什麼樣的差別呢?
Thumbnail
※ 為什麼需要 Subquery? 當⼀個任務需要多個 Query 完成任務,可以使⽤ Subquery 把多個 Query 合併成⼀個 Query。 當我們在進行SQL查詢時,每次查詢都需要在Web Server和資料庫之間來回傳遞資料。這個過程會產生網路延遲,特別是當兩者之間的物理距離較遠時
Thumbnail
※ 何時該使用 JOIN? JOIN 使用的時機是:當你需要同時查詢一張以上的資料表的時候。 ※ SQL有哪些TABLE JOIN的方式? INNER JOIN LEFT JOIN RIGHT JOIN SELF JOIN ※ 使用 JOIN 的時候,我們需要考慮到: 我要使用哪一種
Thumbnail
在進行SQL查詢邏輯更改時,需要適當地使用SubQuery和join來達到新的排序需求。本文將介紹原本的撈取邏輯、需求以及如何使用SubQuery來解決新的排序需求。
Thumbnail
有的時候,會希望在物件導向中對原生的Class新增功能的時候,大多我們都會寫一個新的class並繼承。 但是其實Laravel提供了一個不同的方式,讓我們可以在常用的Class上,直接新增想要的function,那就是macro。
Thumbnail
延伸 MATCHES「|」的 OR 字元應用,我們還可以讓它跟工作表內的範圍做連動,做出更彈性的 QUERY。一起來看看怎麼做吧!
Thumbnail
在用 QUERY 查詢資料時,你曾遇過在 WHERE 寫很多個 OR 的狀況嗎?有個更簡單好用的寫法推薦給你,來瞧瞧!
Thumbnail
本文將介紹 SQL 中的連接(JOIN),連接(JOIN)是用於結合來自兩個或多個資料表的相關數據,建議讀過我之前發佈的幾篇"SQL學習筆記"之後再來看這篇。
Thumbnail
題目敘述 題目會給我們兩張資料表,第一張是Sales,第二張是Product。 第一張是Sales表格,裡面分別有sale_id、 product_id、year、quantity、price等欄位。其中(sale_id、 product_id)做為複合主鍵Primary key Table: