簡體   English   中英

Rails:為什么where(id:objects)有效?

[英]Rails: Why does where(id: objects) work?

我有以下聲明:

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魔術,它旨在提高您的應用程序的性能,而無需了解它的工作原理。


還有一些很酷的優化,比如你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

或者,如果您設置了一個訂單,然后調用最后一個,它將反轉訂單,然后只獲取列表中的最后一個(而不是抓取所有記錄,只給出最后一個記錄)。

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

它為什么有效?

ActiveRecord查詢構建器中的某些內容非常智能,可以看到如果傳遞數組或查詢/條件,則需要構建IN子句。

這記錄在哪里?

是的, http://guides.rubyonrails.org/active_record_querying.html#hash-conditions

2.3.3子集條件

如果要使用IN表達式查找記錄,可以將數組傳遞給條件哈希:

 Client.where(orders_count: [1,3,5]) 

此代碼將生成如下SQL:

 SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5)) 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM