以上的關聯,就是透過 User 和 Skill 的關聯 ,在 view 中一筆一筆去資料庫找相關的 post ,而這每一筆去資料庫的動作,就會有以下的查詢,然後造成 N+1 query 的問題。
N+1就是指說,迴圈中查詢 N 筆資料,加上一開始的第一筆。
123
SkillLoad(0.2ms)SELECT`skills`.*FROM`skills`WHERE`skills`.`user_id` = 1Skill Load (0.2ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`user_id` = 2Skill Load (1.6ms) SELECT `skills`.* FROM `skills` WHERE `skills`.`user_id` = 3
因此要解決這個問題,就能使用以下方式。
includes
includes 主要用於可以直接將相關連的資料,在同一筆查詢,一起撈出來
12345
User.includes(:skills)SELECT`skills`.*FROM`skills`WHERE`skills`.`user_id` IN (1, 2, 3)# 回傳所有 User 和 關聯的 skills
可以看到後面有 IN (1, 2, 3),就是將上面一筆一筆查詢,變成這種方式一次撈出來。這樣在 view 中執行 user.skills 就不會再去資料庫查詢,因為已經都先撈出來了。
1234567891011
#也可以一次 includes 多個關聯User.includes(skills::profile)User.includes(skills:[:cees,:dees])#多重查詢includes(skills::profile).where(date:date).joins(skills::profile).where(skills:{enable:true}).where(profile:{status:true})
joins (inner join)
joins 則是關聯其他資料庫,可以進行查詢,但並不會將關聯的資料拉出來。
1234567
User.joins(:skills)UserLoad(0.4ms)SELECT`users`.*FROM`users`INNERJOIN`skills`ON`skills`.`user_id` = `users`.`id`#回傳所有,有 skill 的 user#因為同一個 user 可能有多個 skill ,這樣就會撈出重複的 user 出來 , 一個 skill 一個 user,因此可以用 .uniq 來去除重複的資料。#如果是一對一就不會有這個問題了