文章轉發自專業的Laravel開發者社區,原始連接:learnku.com/laravel/t/3…php
若是你一直關注個人工做,你就會知道我推崇將咱們的Laravel應用裏面的工做更多地放到數據庫層。 經過在數據庫層完成更多工做,咱們一般能夠減小咱們製造的數據庫查詢的數量,減小應用程序使用的內存量,並減小 Eloquent 處理模型所需的時間。 這能夠帶來一些很是顯着的性能提高。laravel
將更多工做推到數據庫層的一種很好的方法是使用子查詢。 子查詢容許您在另外一個數據庫查詢中運行嵌套查詢。 當沒法經過關係查詢查到結果時,這是獲取輔助模型數據的強大方法,而無需進行任何額外的數據庫查詢。 您還能夠在 order by
語句, where
語句和其餘數據庫子句中使用子查詢。git
在 Laracon US 2019 talk期間, 我參考了我正在使用的查詢構造器,這讓咱們在 laravel 中使用子查詢變得更加簡單. 我已經向 laravel 提交了三個 pr ,將這些添加到 laravel 的內核中.github
概述:數據庫
Pull request #29567 select()
和addSelect()
查詢構建器方法支持子查詢函數
舉個例子,假設咱們有一個目的地表 destinations
和一個到目的地的航班表 flights
。flights
表包含一個 arrival_at
字段,表示航班什麼時候到達目的地。性能
在 Laravel 6.0 中使用了新的子查詢功能,好比要查詢所有目的地 destinations
,以及抵達各目的地最後一班飛機的信息 name
,咱們能夠用單條語句這樣查詢:ui
return Destination::addSelect(['last_flight' => Flight::select('name')
->whereColumn('destination_id', 'destinations.id')
->orderBy('arrived_at', 'desc')
->limit(1)
])->get();
複製代碼
注意這裏是怎麼使用 Eloquent 來生成的子查詢。這樣的語法更好,更具備直觀表現力。一樣的,你也可使用 query builder:spa
return Destination::addSelect(['last_flight' => function ($query) {
$query->select('name')
->from('flights')
->whereColumn('destination_id', 'destinations.id')
->orderBy('arrived_at', 'desc')
->limit(1);
}])->get();
複製代碼
此外, Pull request #29563 使咱們能夠在查詢生成器的 orderBy()
方法中使用子查詢。繼續咱們上面的示例,咱們能夠根據最後一班航班到達目的地的時間對目的地進行排序。code
return Destination::orderByDesc(
Flight::select('arrived_at')
->whereColumn('destination_id', 'destinations.id')
->orderBy('arrived_at', 'desc')
->limit(1)
)->get();
複製代碼
與選擇同樣,您也能夠直接使用查詢構建器來建立子查詢。 例如,您可能但願根據用戶的上次登陸日期訂購:
return User::orderBy(function ($query) {
$query->select('created_at')
->from('logins')
->whereColumn('user_id', 'users.id')
->latest()
->limit(1);
})->get();
複製代碼
最後, Pull request #29602 使咱們在查詢構造器中的 from()
使用子查詢成爲可能。這些有時稱爲派生表。
例如,你可能想要計算應用程序中用戶的平均捐贈總額。 可是,在SQL中,嵌套聚合函數是不可能的:
AVG(SUM(amount))
複製代碼
相反,咱們可使用from子查詢來計算它:
return DB::table(function ($query) {
$query->selectRaw('sum(amount) as total')
->from('donations')
->groupBy('user_id');
}, 'donations')->avg('total');
複製代碼
你可能不須要天天都用到這個,可是當你確實須要它的時候,它是必不可少的。
若是您在Laravel
以外使用Eloquent
,那麼須要注意的一個突破性變化,在Illuminate/Database/Capsule/Manager
對象上 table()
方法有明顯的改變。它已從表 table($table, $connection = null)
更改成表table($table, $as = null, $connection = null)
。
若是您有興趣瞭解更多關於子查詢和其餘高級數據庫技術的信息,請務必關注個人博客,並觀看個人 Laracon US 2019 talk演講。
在Laracon,我還發布了一個新的視頻課程,我正在研究Eloquent的性能模式。本課程的目的是教Laravel開發人員如何把更多的工做推送到數據庫層來大幅提升Laravel應用程序的性能,同時仍然使用Eloquent ORM。若是你感興趣的話,必定要加入郵件列表!