我有以下声明:
Customer.where(city_id: cities)
Run Code Online (Sandbox Code Playgroud)
这导致以下SQL语句:
SELECT customers.* FROM customers WHERE customers.city_id IN (SELECT cities.id FROM cities...
Run Code Online (Sandbox Code Playgroud)
这是预期的行为吗?它在某处记录了吗?我不会使用上面的Rails代码,而是使用以下之一:
Customer.where(city_id: cities.pluck(:id))
Run Code Online (Sandbox Code Playgroud)
要么
Customer.where(city: cities)
Run Code Online (Sandbox Code Playgroud)
这导致完全相同的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
Run Code Online (Sandbox Code Playgroud)
基本上,这种方式会发出两个SQL语句:
select * from users where age = 30;
select * from memberships where user_id in (1, 2, 3);
Run Code Online (Sandbox Code Playgroud)
其中每个都涉及在应用程序和数据之间的网络端口上调用,然后通过同一端口传回.
这会更有效:
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
Run Code Online (Sandbox Code Playgroud)
它将构建一个单独的嵌套查询,因此它只需要对数据库进行一次往返.
select * from memberships
where user_id in (
select id from users where age = 30
);
Run Code Online (Sandbox Code Playgroud)
所以,是的,这是预期的行为.它有点像Rails魔术,它旨在提高您的应用程序的性能,而无需了解它的工作原理.
还有一些很酷的优化,比如你打电话first或last代替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
Run Code Online (Sandbox Code Playgroud)
或者,如果您设置了一个订单,然后调用最后一个,它将反转订单,然后只获取列表中的最后一个(而不是抓取所有记录,只给出最后一个记录).
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
Run Code Online (Sandbox Code Playgroud)
它为什么有效?
ActiveRecord查询构建器中的某些内容非常智能,可以看到如果传递数组或查询/条件,则需要构建IN子句.
这记录在哪里?
是的,http://guides.rubyonrails.org/active_record_querying.html#hash-conditions
如果要使用IN表达式查找记录,可以将数组传递给条件哈希:
Run Code Online (Sandbox Code Playgroud)Client.where(orders_count: [1,3,5])此代码将生成如下SQL:
Run Code Online (Sandbox Code Playgroud)SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5))
| 归档时间: |
|
| 查看次数: |
62 次 |
| 最近记录: |