ruby-on-rails - How to avoid N + 1 queries with self-referential table in Rails
问题描述
How to I correctly use includes
to avoid N + 1 queries in this situation:
I have a set of categories that can be nested (i.e., they form a tree). For example:
- Teaching
- Course 1
- Office Hours
- Lecture
- Course 2
- Office Hours
- Lecture
- Course 1
- Research
- Project 1
- Project 2
- Service
To set up this hierarchy, each Category
record has parent_id
as a foreign key.
This is my Rails model:
class Category < ApplicationRecord
belongs_to :user
belongs_to :parent, class_name: "Category", optional: true
has_many :children, class_name: "Category", foreign_key: "parent_id"
end
I access all the categories for a given user using
@categories = Category.includes(:children).where(user_id: user.id)
However, every call to @categories[i].children
generates a new query.
How do I correctly use includes
so that I can access each category's child categories without additional queries.
(I also tried @categories = Category.where(user_id: user.id).includes(:children)
with no change in behavior.)
解决方案
You must use joins
too, so you're able to use the relationship between categories
and the so called children_categories
:
Category.includes(:children).joins(:children).where(user_id: <user_id>)
# SELECT "categories"."id" AS t0_r0,
# ...
# "children_categories"."id" AS t1_r0,
# ...
# FROM "categories"
# INNER JOIN "categories" "children_categories"
# ON "children_categories"."parent_id" = "categories"."id"
# WHERE "categories"."user_id" = $1
Otherwise you'll see what I think is your problem now:
Category.includes(:children).where(user_id: <user_id>)
# SELECT "categories".* FROM "categories" WHERE "categories"."user_id" = $1
# SELECT "categories".* FROM "categories" WHERE "categories"."parent_id" IN ($1, $2, ...)
推荐阅读
- c++ - 如何在编译时在 QT 中创建 SQLlite 表并在其中插入数据?
- maven - 无法使用本地安装的 Maven 原型构建项目
- c++ - 使用 SIMD 对半字节的去交错向量
- python - 芹菜+芹菜工人的问题
- javascript - fullCalendar 资源未显示
- go - 如何从 IP 获取系统接口名称
- django - 如何仅本地化数字?
- javascript - 当我在 Chrome 中打开一个 THREE.js 应用程序时,我的浏览器拖得很糟糕
- java - 如果返回 Http 401 再次调用 API
- python - Scrapy 如何在 Jupyter notebook 上工作?