Laravel with() vs join()

更新 發佈閱讀 9 分鐘

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


資料情境:

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

raw-image
raw-image
raw-image

程式碼:

raw-image
raw-image


<?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);
}
}
}



實驗結果:

raw-image
  • 從結果可以看出,with這種寫法,共下了兩次sql,分別把文章跟留言都撈出來,再把資料mapping起來,with_result如下:
raw-image
raw-image
  • join寫法就不多解釋了,join_result如下:
raw-image
  • 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
留言分享你的想法!
avatar-img
Vic Lin的沙龍
20會員
161內容數
Vic Lin的沙龍的其他內容
2023/08/13
父元件 傳遞方法使用@ <template>    ...    <Login @modalClose="modalClose"/> ... </template> <script setup>     const _modal = ref();     function m
2023/08/13
父元件 傳遞方法使用@ <template>    ...    <Login @modalClose="modalClose"/> ... </template> <script setup>     const _modal = ref();     function m
2023/03/25
前情提要 由於我的筆電已經用了10年,無法再戰下去了,且有預算考量,加上使用電腦幾乎都是定點,只有偶爾回家的時候會需要攜帶,因此最終選擇了迷你電腦,體積小不占空間,又方便攜帶,剛好符合我的需求。 菜單 由於這台無法裝獨顯,所以CPU的部分選擇 AMD R5 3400G(含Vega 11內
Thumbnail
2023/03/25
前情提要 由於我的筆電已經用了10年,無法再戰下去了,且有預算考量,加上使用電腦幾乎都是定點,只有偶爾回家的時候會需要攜帶,因此最終選擇了迷你電腦,體積小不占空間,又方便攜帶,剛好符合我的需求。 菜單 由於這台無法裝獨顯,所以CPU的部分選擇 AMD R5 3400G(含Vega 11內
Thumbnail
2023/03/10
Nuxt3中可使用useFetch來獲取數據,不須再引用axios,相當方便: 本筆記參考: https://juejin.cn/post/7104071421160063012 https://juejin.cn/post/7086472647575339045
2023/03/10
Nuxt3中可使用useFetch來獲取數據,不須再引用axios,相當方便: 本筆記參考: https://juejin.cn/post/7104071421160063012 https://juejin.cn/post/7086472647575339045
看更多
你可能也想看
Thumbnail
本篇純粹紀錄實作流程,以方便未來可以照此版繼續優化改進作法,這篇會使用Laravel 9版本並搭配Boostrap 5來做開發。 發現將每一次的實作作筆記,回頭再看的時候,就可以發現實作差異並進行改正,沒搞懂的底層操作也能在覆盤的時候理解,建議大家都要筆記自己的實作流程。
Thumbnail
本篇純粹紀錄實作流程,以方便未來可以照此版繼續優化改進作法,這篇會使用Laravel 9版本並搭配Boostrap 5來做開發。 發現將每一次的實作作筆記,回頭再看的時候,就可以發現實作差異並進行改正,沒搞懂的底層操作也能在覆盤的時候理解,建議大家都要筆記自己的實作流程。
Thumbnail
本篇深入探討了Model的基本定義、其Controller的關係,以及如何在Controller中使用Model進行CRUD操作。強調了Model的關聯方法,如hasMany,並透過範例程式碼展示了其實際應用。為初學者提供了一個清晰的Laravel入門路徑,同時也為有經驗的開發者提供了實用的參考。
Thumbnail
本篇深入探討了Model的基本定義、其Controller的關係,以及如何在Controller中使用Model進行CRUD操作。強調了Model的關聯方法,如hasMany,並透過範例程式碼展示了其實際應用。為初學者提供了一個清晰的Laravel入門路徑,同時也為有經驗的開發者提供了實用的參考。
Thumbnail
Laravel的Model是資料和邏輯的核心連接,簡化資料庫操作。本指南著重於Model的基本屬性、方法和Eloquent ORM的使用。我們詳細探討了hasMany、hasOne和belongsTo這些關聯,它們基於外鍵確定資料間的關係。透過本文,您將深入了解如何有效地在Laravel中使用Mod
Thumbnail
Laravel的Model是資料和邏輯的核心連接,簡化資料庫操作。本指南著重於Model的基本屬性、方法和Eloquent ORM的使用。我們詳細探討了hasMany、hasOne和belongsTo這些關聯,它們基於外鍵確定資料間的關係。透過本文,您將深入了解如何有效地在Laravel中使用Mod
Thumbnail
假設資料如下: local DB裡面的test Collection SELECT SELECT可以這樣寫: 由於config/database.php中設定的default DB_CONNECTION是mysql,所以這邊特別指定使用mongodb connection。 回傳結果如下: 軟刪除
Thumbnail
假設資料如下: local DB裡面的test Collection SELECT SELECT可以這樣寫: 由於config/database.php中設定的default DB_CONNECTION是mysql,所以這邊特別指定使用mongodb connection。 回傳結果如下: 軟刪除
Thumbnail
如果你 WHERE 的條件需要常常更動,但每次都要進去 QUERY 所在的儲存格編輯語法,實在是有點太麻煩了?但其實有個小技巧,可以讓 QUERY 更新得更輕鬆。來看看吧!
Thumbnail
如果你 WHERE 的條件需要常常更動,但每次都要進去 QUERY 所在的儲存格編輯語法,實在是有點太麻煩了?但其實有個小技巧,可以讓 QUERY 更新得更輕鬆。來看看吧!
Thumbnail
本篇主要是要探討,with/has/whereHas/doesntHave/whereDoesntHave之間的差別,以部落格文章及留言的例子來看。 資料情境: 程式碼與結果: with是把所有文章跟留言都找出來。 has是把所有有留言的文章找出來,不包含留言。
Thumbnail
本篇主要是要探討,with/has/whereHas/doesntHave/whereDoesntHave之間的差別,以部落格文章及留言的例子來看。 資料情境: 程式碼與結果: with是把所有文章跟留言都找出來。 has是把所有有留言的文章找出來,不包含留言。
Thumbnail
之前在執行某些專案的時候,常看到->with()這種寫法,因此一直都很好奇到底跟->join()寫法有什麼差別,哪一種寫法效能比較好呢? 資料情境: 假設現在情境是要撈出文章跟留言,目前共有2篇文章,每篇各有4萬筆留言,也就是留言table共有8萬筆資料: 程式碼: 實驗結果: 結論:
Thumbnail
之前在執行某些專案的時候,常看到->with()這種寫法,因此一直都很好奇到底跟->join()寫法有什麼差別,哪一種寫法效能比較好呢? 資料情境: 假設現在情境是要撈出文章跟留言,目前共有2篇文章,每篇各有4萬筆留言,也就是留言table共有8萬筆資料: 程式碼: 實驗結果: 結論:
Thumbnail
如下圖範例,在最後->get()之後加上->keyBy('id'),可以把id這個欄位變成key,在資料處理過程很好用。 本筆記參考: 1. https://stackoverflow.com/questions/26865877/laravel-eloquent-return-array-ke
Thumbnail
如下圖範例,在最後->get()之後加上->keyBy('id'),可以把id這個欄位變成key,在資料處理過程很好用。 本筆記參考: 1. https://stackoverflow.com/questions/26865877/laravel-eloquent-return-array-ke
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News