使用預載入最佳化 Laravel Model 查詢

godruoyi發表於2017-08-07

file

原文譯自eloquent-eager-loading,簡化其前面構造資料部分。

介紹

物件關係對映(ORM)使資料庫的工作變得非常簡單。 在以物件導向的方式定義資料庫關係時,可以輕鬆查詢相關的模型資料,開發人員可能不會注意底層資料庫呼叫。

下面將透過一些例子,進一步幫助您瞭解如何最佳化查詢。

假設您從資料庫收到了100個物件,並且每個記錄都有1個關聯模型(即belongsTo)。 預設使用ORM將產生101個查詢; 如下所示:

//獲取已釋出的100條文章
$posts = Post::limit(100)->get(); //一次查詢

$authors = array_map(function($post) {
    // 對作者模型生成查詢
    return $post->author->name;
}, $posts);

我們在查詢時沒有告訴Post模型,我們還需要所有的作者,所以每次從單個Post模型例項獲取作者的名字時,都會發生單獨的查詢。

array_maps時發生100次查詢,加上先前一次查詢,累計產生101次查詢。

預載入

接下來,如果我們打算使用關聯的模型資料,我們可以使用預載入將該101個查詢總數減少到2個查詢。 只需要告訴模型你需要什麼來載入。如下:

//獲取已釋出的100條文章  - 並預載入文章對應作者
$posts = Post::with('author')->limit(100)->get();//2次查詢

$authors = array_map(function($post) {
    // 對作者模型生成查詢
    return $post->author->name;//這裡講不在產生查詢
}, $posts);

如果你開啟了sql日誌,你將看到上述預載入將只會產生兩條查詢:

select * from `posts`
select * from `authors` where `authors`.`id` in (?, ?, ?, ?, ?) [1,2,3,4,5]

如果您有多個關聯模型,則可以使用陣列載入它們:

$posts = App\Post::with(['author', 'comments'])->get();

接下來我們重新定義如下關係

Post -> belongsTo -> Author //每個文章只屬於一個使用者
Author -> hasMany -> Post   //每個使用者擁有多個文章
Author -> hasOne -> Profile //每個使用者只有一個簡介

考慮下述情況:獲取已釋出文章所屬作者的個人簡介。

//獲取所有文章 - 並預載入文章對應作者
$posts = App\Post::with('author')->get();//兩次查詢

//根據每個 `作者` 獲取其簡介
$posts->map(function ($post) {
    //雖然我們直接透過$author = $post->author不會產生查詢,
    //但當呼叫$author->profile時,每次都會產生一個新查詢
    return $post->author->profile;
});

假設上述App\Post::with('author')->get()有100條記錄,將會產生多少條查詢呢?

透過最佳化預載入,我們可以避免巢狀關係中的額外查詢。

//獲取所有文章 - 並預載入文章對應作者及每個作者對應的 profile
$posts = App\Post::with('author.profile')->get();//三次查詢

$posts->map(function ($post) {
    //不在產生新查詢
    return $post->author->profile;
});

你可以開啟你的sql日誌看到對應的三條查詢。

select * from `posts`  
select * from `authors` where `authors`.`id` in (?, ?, ?, ?, ?) [.....] 
select * from `profiles` where `profiles`.`author_id` in (?, ?, ?, ?, ?) [.....] 

懶惰載入

有時候您可能只需要根據條件收集相關聯的模型。 在這種情況下,您可以懶惰地呼叫相關資料的其他查詢:

$posts = App\Post::all();//一次查詢

$posts->load('author.profile');//兩次查詢
$posts->map(function ($post) {
    //不在產生新查詢
    return $post->author->profile;
});

檢視您的sql日誌,總共看到三個查詢,但只有呼叫$posts->load()時才會顯示。

結論

希望您更加了解有關載入型號的更多資訊,並瞭解其在更深層次上的工作原理。 Laravel相關的文件已經很全面了,希望額外的實踐練習可以幫助您更有信心最佳化關係查詢。


本作品採用《CC 協議》,轉載必須註明作者和本文連結
二愣的閒談雜魚

相關文章