我有这个代码,它执行了大量的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
我在最多的方法中有大量的查询,我想知道,如果我能以某种方式减少这些问题?
编辑:
我看到的主要问题是大多数相关的 - 它执行了大量查询,见下文:
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 :(得分:0)
我不确定没有看到你的应用正在进行的SQL查询,但我怀疑它在这部分代码中遇到了 N + 1查询问题:
self.items.each do |item|
ids << item.categories.pluck(:id)
end
这将为每个Item执行单独的查询以获取其关联的类别(这就是为什么您会看到这么多SELECT "categories"."id" ...
个查询)。但是,仅在两个查询中选择所有项目的类别会更有效。
在上面的代码中可能还有其他实例,但一般来说,N + 1查询问题的解决方案是在从DB中获取“父”模型时使用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
答案 1 :(得分:0)
尝试划分句子
Item.includes(:categories).where("categories.id IN (?)", self.purchased_categories).references(:categories).uniq
分为两个,一个用于所有项目的ID,另一个用于所有类别,通过项目和类别之间的表格,如
1. Item.includes(:categories).where("categories.id IN (?)", self.purchased_categories)
2. Category.includes(:items).where("items.id IN (?)", <THE ids of Items>)