N+1
是ORM(對象關係映射)世界中的一個問題。sql
在介紹什麼是N+1
問題以前,首先思考一個問題:數據庫
假設如今有一個用戶表和一個餘額表,這兩個表經過user_id
進行關聯。如今有一個需求是查詢年齡大於18歲的用戶,以及用戶各自的餘額。框架
這個問題並不難,但對於新手而言,可能經常會犯的一個錯誤就是在循環中進行查詢。性能
$users = User::where("age", ">", 18)->select(); foreach($users as $user){ $balance = User::getFieldByUserId($user->user_id, "balance"); $user['balance'] = $balance; }
這樣作是很是糟糕的,數據量小還少,在數據量較大的狀況下,是很是消耗數據庫性能的。this
經過Mysql 查詢日誌,能夠看到查詢用戶表是一次,由於有四個符合該條件的用戶,查詢用戶表關聯的餘額表是四次。spa
N+1
問題就是這樣產生的:查詢主表是一次,查詢出N 條記錄,根據這N 條記錄,查詢關聯的副(從)表,共須要N 次。因此,應該叫1+N
問題更合適一些。日誌
其實,若是稍微瞭解一點SQL,根本不用這麼麻煩,直接使用JOIN
一次就搞定了。code
有時候是否是以爲ORM 也挺礙事的。對象
對於這類問題,ORM 其實爲咱們提供了相應的方案,那就是使用with
。blog
$users = User::where("age", ">", 18) ->with("hasBalance") ->select();
hasBalance
是什麼呢?
它是在User
模型中定義的一個方法:
class User extends Model { // ... public function hasBalance() { return $this->hasOne(Balance::class, "user_id", "user_id"); } }
經過這個方法讓User
模型與Balance
模型進行一對一關聯。
如今再來看一下Mysql 的查詢日誌:
能夠很清楚的看到,總查詢次數由原來的1+N
變成了如今的1+1
。
N+1
問題是什麼?會形成什麼影響?應該如何解決?
with
去解決