ruby-on-rails - rails : Why does where(id: objects) work?

标签 ruby-on-rails

我有以下声明:

Customer.where(city_id: cities)

这导致以下 SQL 语句:
SELECT customers.* FROM customers WHERE customers.city_id IN (SELECT cities.id FROM cities...

这是预期的行为吗?它在某处记录了吗?我不会使用上面的 Rails 代码,而是使用以下代码之一:
Customer.where(city_id: cities.pluck(:id))

或者
Customer.where(city: cities)

这导致完全相同的 SQL 语句。

最佳答案

AREL 查询库允许您将 ActiveRecord 对象作为捷径传递。然后它将它们的主键属性传递到它用来联系数据库的 SQL。

查找多个对象时,AREL 库将尝试在尽可能少的数据库往返中查找信息。它通过将您正在执行的查询作为一组条件来执行此操作,直到需要检索对象为止。

这种方式效率低下:

users = User.where(age: 30).all
#                           ^^^ get all these users from the database
memberships = Membership.where(user_id: users)
#                                       ^^^^^ This will pass in each of the ids as a condition

基本上,这种方式会发出两条 SQL 语句:
select * from users where age = 30;
select * from memberships where user_id in (1, 2, 3);

其中每一个都涉及应用程序之间网络端口的调用,然后数据将通过同一端口传回。

这会更有效率:
users = User.where(age: 30)
# This is still a query object, it hasn't asked the database for the users yet.
memberships = Membership.where(user_id: users)
# Note: this line is the same, but users is an AREL query, not an array of users

相反,它将构建一个单一的嵌套查询,因此它只需往返数据库一次。
select * from memberships 
where user_id in (
  select id from users where age = 30
);

所以,是的,这是预期的行为。这有点像 Rails 魔法,它旨在提高应用程序的性能,而您无需了解它的工作原理。

还有一些很酷的优化,比如如果你打电话 firstlast而不是 all ,它只会检索一个记录。
User.where(name: 'bob').all
# SELECT "USERS".* FROM "USERS" WHERE "USERS"."NAME" = 'bob'
User.where(name: 'bob').first
# SELECT "USERS".* FROM "USERS" WHERE "USERS"."NAME" = 'bob' AND ROWNUM <= 1

或者,如果您设置了一个顺序,并调用 last,它将颠倒顺序然后只抓取列表中的最后一个(而不是抓取所有记录并只给您最后一个)。
User.where(name: 'bob').order(:login).first
# SELECT * FROM (SELECT "USERS".* FROM "USERS" WHERE "USERS"."NAME" = 'bob' ORDER BY login) WHERE ROWNUM <= 1
User.where(name: 'bob').order(:login).first
# SELECT * FROM (SELECT "USERS".* FROM "USERS" WHERE "USERS"."NAME" = 'bob' ORDER BY login DESC) WHERE ROWNUM <= 1
# Notice, login DESC

关于ruby-on-rails - rails : Why does where(id: objects) work?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49296875/

相关文章:

ruby-on-rails - rails : Install and configure bootstrap on rails 6

ruby-on-rails - 嵌套 form_for

ruby-on-rails - 在模型上使用 if 和范围

ruby-on-rails - 请求另一台服务器获取 ruby​​ on Rails 中存在的文件

ruby-on-rails - 将 Rails/ClearDB App 推送到 Heroku 错误 'Can' t 连接到 '127.0.0.1' 上的 MySQL 服务器

ruby-on-rails - Ruby on Rails-渲染布局

ruby-on-rails - 使用 ruby​​/rails 将文件上传到网站

ruby-on-rails - Rails 中的字符串输入日期错误消息

mysql - 如何计算使用acts_as_taggable标签标记的项目数量

ruby-on-rails - Rails协会has_one最新记录