为了进行单个数据库查询,我渴望加载 Posts 及其翻译数据(使用 Rails 6 和 Mobility (*)),但它产生了 2 个 SQL 查询:
# app/models/post.rb
class Post < ApplicationRecord
extend Mobility
translates :title, :description, backend: :table
end
# app/controllers/posts_controller.rb
class PostsController < ApplicationRecord
def index
@posts = Post.eager_load(:translations).limit(3)
end
end
<%# app/views/posts/index.html.erb %>
<% @posts.each do |post| %>
<h1><%= post.title %></h1>
<div><%= post.description %></div>
<% end %>
结果:
- 首先,选择所有 Post ID
- 然后使用 WHERE IN 返回具有这些 ID 的帖子的所有属性
SELECT DISTINCT "posts"."id" FROM "posts"
LEFT OUTER JOIN "post_translations"
ON "post_translations"."post_id" = "posts"."id" LIMIT $1 [["LIMIT", 3]]
SELECT "posts"."id" AS t0_r0, "posts"."created_at" AS t0_r1, "posts"."updated_at" AS t0_r2, "post_translations"."id" AS t1_r0, "post_translations"."locale" AS t1_r1, "post_translations"."created_at" AS t1_r2, "post_translations"."updated_at" AS t1_r3, "post_translations"."title" AS t1_r4, "post_translations"."description" AS t1_r5, "post_translations"."post_id" AS t1_r6 FROM "posts"
LEFT OUTER JOIN "post_translations"
ON "post_translations"."post_id" = "posts"."id"
WHERE "posts"."id" IN ($1, $2, $3) [["id", "00060a7d-b846-5fc5-a372-1fc3462c695c"], ["id", "008db504-6fb4-5e90-bdca-4293ebe6d920"], ["id", "034944c1-4067-5ae5-89aa-4777ef14d66b"]]
如何避免这种带有内存中 ID 的双重 SQL 语句?
(*) 注意 mon Mobility
Mobility 文档中有生成单个 SQL 语句的示例,但正如 Chris Salzberg 所指出的,在此示例中根本没有使用它的查询 API,因此不应该是罪魁祸首。为了证明该问题可能与 Mobility 无关,而是与 Active Record 本身有关,下面是从 Mobility 中剥离出来的一些等效代码,它显示了相同的双重查询问题(注意:这只是为了演示目的,就像我一样想继续使用 Mobility):
class Post < ApplicationRecord
has_many :translations, ->{ where(locale: I18n.locale) }
%i(title description).each do |attr|
define_method(attr) do
translations.first.send(attr)
end
end
class Translation < ApplicationRecord; end
end
<%# app/views/posts/index.html.erb %>
<% Post.eager_load(:translations).limit(3).each do |post| %>
<h1><%= post.title %></h1>
<div><%= post.description %></div>
<% end %>