2013-04-09 86 views
1

我有這段代碼,它正在執行大量的SQL查詢,尤其是使用最後一種方法('最相關的')。我下面的設置是這樣的:在查找關聯記錄時減少查詢

class User < ActiveRecord::Base 
    authenticates_with_sorcery! 
    has_and_belongs_to_many :items 


    def purchased_categories 
    ids = [] 
    self.items.each do |item| 
     ids << item.categories.pluck(:id) 
    end 
    ids.flatten.uniq 
    end 

    def recommended_items 
    Item.includes(:categories).where("categories.id IN (?)",  self.purchased_categories).references(:categories).uniq - self.items 
    end 

    def most_related 
    cs = self.purchased_categories 
    self.recommended_items.sort { |a, b| (a.categories.pluck(:id) & cs).length <=> (b.categories.pluck(:id) & cs).length } 
    end 

end 

我的產品型號看起來如下:

class Item < ActiveRecord::Base 
    has_and_belongs_to_many :categories 
    has_and_belongs_to_many :users 
end 

我有一噸的查詢在most_related方法,我想知道,如果我能減少那些不知何故?

編輯:

的主要問題我看到的是most_related - 它執行查詢的一噸,見下圖:

Item Load (4.1ms) SELECT "items".* FROM "items" INNER JOIN "items_users" ON "items"."id" = "items_users"."item_id" WHERE "items_users"."user_id" = $1 [["user_id", 815249]] 
    (0.9ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1253]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1253]] 
    SQL (2.9ms) SELECT DISTINCT "items"."id" AS t0_r0, "items"."name" AS t0_r1, "items"."created_at" AS t0_r2, "items"."updated_at" AS t0_r3, "categories"."id" AS t1_r0, "categories"."name" AS t1_r1, "categories"."created_at" AS t1_r2, "categories"."updated_at" AS t1_r3 FROM "items" LEFT OUTER JOIN "categories_items" ON "categories_items"."item_id" = "items"."id" LEFT OUTER JOIN "categories" ON "categories"."id" = "categories_items"."category_id" WHERE (categories.id IN (134,152)) 
    (0.8ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1684]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1596]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1596]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1684]] 
    (0.4ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1622]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1685]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.8ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1683]] 
    (0.7ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.7ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1378]] 
    (0.7ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1594]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.4ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1678]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1428]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1427]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1623]] 
    (0.4ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1676]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1456]] 
    (0.7ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1532]] 
    (1.1ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1546]] 
    (0.4ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1641]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1681]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.7ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1677]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.8ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1288]] 
    (0.7ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1533]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1686]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1643]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1679]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1682]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.8ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1687]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1675]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1376]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1549]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1680]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1750]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1643]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1623]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1623]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1596]] 
    (0.7ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1533]] 
    (0.7ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1623]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1532]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1623]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1378]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1623]] 
    (0.5ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1622]] 
    (0.6ms) SELECT "categories"."id" FROM "categories" INNER JOIN "categories_items" ON "categories"."id" = "categories_items"."category_id" WHERE "categories_items"."item_id" = $1 [["item_id", 1623]] 
+0

你可以粘貼一些你看到的重複查詢的樣本在軌道控制檯? – 2013-04-09 05:58:21

+0

添加了最麻煩的查詢。我比擔心購買的類別更擔心。 – 2013-04-09 06:06:51

+0

但是Most_related calls called_categories – 2013-04-09 06:17:27

回答

0

我不能肯定,沒有看到確切的SQL查詢中你的應用程序是做,但我懷疑它是從N + 1查詢問題苦難的這部分代碼:

self.items.each do |item| 
    ids << item.categories.pluck(:id) 
end 

這將PERF orm單獨查詢每個項目以獲取其關聯的類別(這就是爲什麼您看到很多SELECT "categories"."id" ...查詢)。但是,只需在兩個查詢中選擇其所有項目即可。

上面的代碼中可能有其他情況,但通常N + 1查詢問題的解決方案是在從數據庫中獲取「父」模型時使用includes(...)。請閱讀Eager Loading Associations的Rails指南部分。

編輯:它可能是更有效地使用has_many :through而不是has_and_belongs_to_many這些模型的關係,以及可能有助於使查詢也更容易解決您的問題。如果您切換到has_many :through你會最終有這樣的事情(有一個更簡單的purchased_categories法):

class User 
    has_many :items 
    has_many :categories, :through => :items 

    def purchased_categories 
    category_ids 
    end 
end 

class Item 
    belongs_to :user 
    belongs_to :category 
end 
+0

問題在於,一個項目有多個類別。所以我似乎有這個問題。 – 2013-04-09 06:36:40

0

嘗試了一句

Item.includes(:categories).where("categories.id IN (?)", self.purchased_categories).references(:categories).uniq 

分爲兩種,一種爲所有的IDS項目和其他所有類別通過項目和類別之間的表,如

1. Item.includes(:categories).where("categories.id IN (?)", self.purchased_categories) 
2. Category.includes(:items).where("items.id IN (?)", <THE ids of Items>)