2015-09-04 58 views
1

我有一些n + 1查詢使得我的網站的加載時間非常緩慢。這是一個像Facebook一樣的社交媒體網站,n + 1查詢的來源是朋友。詳細信息 -Rails - 在沒有表連接的情況下消除n + 1個查詢

友誼表有3列 - User_id(發送請求的用戶),friend_id(獲取請求的用戶)以及掛起的布爾值,表示友誼是否被接受。

朋友請求使用

def friend_requests 
    friend_ids = Friendship.where('friend_id = ? AND pending = true', self.id).all 
end 

我特別需要的友誼ID,因爲我需要,如果用戶要接受或拒絕請求,更新掛起的布爾在我的用戶模型來實現。

友誼模型聲明瞭belongs_to =>好友關聯。

belongs_to :friend, 
    class_name: "User", 
    foreign_key: :friend_id, 
    primary_key: :id 

n + 1的來源。對於該視圖,當我想要獲取用戶收到的好友請求時,我還想包括髮送請求的用戶的姓名和個人資料圖片。它看起來像這樣一些事情 -

json.friend_requests @user.friend_requests.includes(friend: :name) do |friendship| 
    json.extract! friendship, :id, :user_id 
    json.name User.find(friendship.user_id).name # n + 1 
    json.profile_pic User.find(friendship.user_id).profile_piC# n + 1 
end 

我本來約的語法有些疑惑包括(朋友:名),但我已經試過在this thread提到的所有排列,但它給了我

在用戶上找不到名爲'name'的關聯;也許你拼錯了 呢?

哪個是正確的,因爲name是User的屬性而不是關聯。

的唯一方式,以便解決這個問題,我能想到的,是我改變我的friend_requests表看起來像這樣的find_by_sql查詢 -

SELECT f.id, f.user_id, f.friend_id, f.pending, users.name, users.profile_pic 
FROM friendship AS f 
JOIN users ON users.id = friendship.friend_id 
WHERE f.friend_id = ? AND pending = true 

它會給我的名字和profile_pic用戶,但我不想這樣做,因爲它看起來髒,但更重要的是,我想知道是否有更好,更聰明的方式來做到這一點。

+0

半相關http://stackoverflow.com/a/26251892/525478 –

回答

2

從API文檔上#includes

指定的關係將包含在結果集。

關鍵字是關係:您指定要包括一個整體的關係,而不是一個領域。

你應該試試這個:

@user.friend_requests.includes(:friend) do |friendship| 

    # whatever you need before 

    # access the friend's name through the friend relationship 
    # this should not require another query as the friend object was 
    # preloaded into friendship using #includes 
    friendship.friend.name 

    # whatever you need after 

end 

編輯:實際上,這將觸發2個SQL查詢,第一個來獲取用戶的friend_requests,再進行第二次同時得到所有friend關係。 使用所有在第一friend_requests查詢中找到的id形式

SELECT "users".* FROM "users" WHERE "users"."id" IN (/*LIST OF IDs*/) 

的第二個查詢之中。

如果你想只有一個查詢將被解僱,你應該嘗試一個JOIN,大概是這個樣子:

@user.friend_requests.joins(:friend).includes(:friend) 
相關問題