Join and Includes
我們在開發的時候免不了關聯資料庫,在撈資料的時候也常常會需要用到 joins 跟 includes
所以,我們什麼時候會用到 joins 跟 includes
- 要尋找跟其他 model 有關聯的資料
- 避免 N + 1 問題
** N + 1 問題是什麼呢?
當我們查詢多筆資料時,資料庫會先將所有的資料撈出,並一個一個去比對,就會有 N(筆資料) + 1(次撈出全部) 的問題存在
joins 跟 includes 有什麼差別?
joins 跟 includes 其實有蠻大的差別,
不過因為他們都是在查詢關聯資料,所以我們很常搞混,
不過搞懂他們的差別就會知道什麼時候該派誰上場。
** lazy loading:並不會一開始就載入所有資料,而是需要用到的時候才會去收集並載入
** eager loading:一開始就把需要的資料都載入,需要時就可以從 Cache 中拿取
先來說結論:joins 只會去比對資料,而 includes 會去查詢有關聯的資料,並存到 cache 中
那我們來看一下實際使用吧
joins
使用 joins 時,會去「比對」Tag 中有 post_id 的資料
1 | find_tags = Post.joins(:tags) |
當我們需要這包資料時,
這時會再去資料庫撈一次資料,把有 tag 的資料撈出來呈現
1 | find_tags.each do |post| |
看起來是不是很沒效率呢?
那我們來看看 includes 會怎麼運作
includes
使用 includes 時,會去把所有 Tag 的資料一次撈出並查詢哪些有 post_id
1 | find_tags = Post.includes(:tags) |
當我們需要使用這包資料時,
會直接從 Cache 中拿出這包已經處理好的資料
1 | find_tags.each do |post| |
由上述例子可以知道, includes 在查詢及撈資料的過程都相對有效率
所以用 includes 就比較好嗎?
要看使用的狀況,以剛剛的 Post 及 Tag 例子來看
我們改變一下需求,要撈出有 tag 的 post 資料,只需要呈現特定 tag 的 post 資訊
joins
這時候 joins 只有去比對條件,並沒有去撈出資料
1 | find_tags = Post.joins(:tags).where(tag: {name: 'hello'}) |
includes
使用 includes ,會到資料庫將所有有關聯的資料撈出來做一次查詢
1 | find_tags = Post.includes(:tags).where(tag: {name: 'hello'}) |
在不需要印出關聯資料庫的資料狀況時, joins 只有去比對資料,並沒有撈資料的動作,所以會比 includes 更有效率。
結論
在查詢關聯資料時,joins 只會去比對資料,而 includes 則會去查詢有關聯的資料並存到 Cache 中。在實際使用中,joins 會比 includes 更加高效,特別是當我們不需要印出關聯資料時。