[英]Rails3 ActiveRecord - Fetching all records that have A and B (through a has_many relationship)
[英]Rails 4 has_many associations w/Postgres: query table A for all records that actually have B, C, and D
给定具有多个has_many
关联的模型,如下所示:
class Route < ActiveRecord::Base
has_many :flights
has_many :deals
has_many :ratings
...
end
鉴于这样一个场景,不是所有的路线其实都3,有一个简单的方法来发现, 确实有所有3条路线的数量?
基于其他SO问题,我尝试了以下方法: scope :active, -> { joins(:ratings).joins(:deals).joins(:flights)
。 然后,我在控制台中调用Route.active.count
,但是该过程挂起了。 这些表很大,所以我假设它与它有关。 航班有2,037,031行; 交易共有659,804行; 评分为141,879。
是否有更快/更好的方法来获取所需的数量(具有航班,交易和等级的路线数量)?
编辑
以下是相关的架构信息:
create_table "routes", force: true do |t|
t.integer "from_id"
t.integer "to_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "routes", ["from_id"], name: "index_routes_on_from_id", using: :btree
add_index "routes", ["to_id"], name: "index_routes_on_to_id", using: :btree
create_table "ratings", force: true do |t|
# various columns...
t.datetime "created_at"
t.datetime "updated_at"
t.integer "route_id"
end
add_index "ratings", ["route_id"], name: "index_ratings_on_route_id", using: :btree
create_table "flights", force: true do |t|
t.integer "airline_id"
t.integer "route_id"
# various columns...
end
add_index "flights", ["airline_id"], name: "index_flights_on_airline_id", using: :btree
add_index "flights", ["route_id"], name: "index_flights_on_route_id", using: :btree
create_table "deals", force: true do |t|
t.integer "route_id"
# various columns...
end
add_index "deals", ["route_id"], name: "index_deals_on_route_id", using: :btree
编辑
我将布尔属性添加到不flightless
和不ratingless
的路线表中,以帮助在导入路线是否有航班或评级后更轻松地进行跟踪。 之后,我尝试了一些不同的查询并获得了不同的计数:
[7] pry(main)> Route.where(flightless: false, ratingless: false).includes(:deals).count
=> 19415
[8] pry(main)> Route.where(flightless: false, ratingless: false).joins(:deals).distinct.count
=> 10243
[9] pry(main)> Route.where(flightless: false, ratingless: false).joins(:deals).count
=> 378737
第8行的查询产生的结果与下面第一个答案中Nic的纯SQL建议相同。 我想我理解第9行的查询为什么返回的方式超出了可能的正确性(每个路由都会为其连接到的每个资源重复),但是我不理解joins
之间的区别,并且includes
足以说明为什么joins...distinct
产生的答案不同于此处includes
答案。
使用joins
和includes
将生成笛卡尔积,这将需要一些内存,并且取决于可用资源会使服务器无响应。 由于您是在计算而不是实际的记录,因此检查它们的存在应该足够了,尽管可能以更多的计算为代价:
Route.where('EXISTS (SELECT 1 FROM ratings WHERE routes.id = ratings.route_id)
AND EXISTS (SELECT 1 FROM deals WHERE routes.id = deals.route_id)
AND EXISTS (SELECT 1 FROM flights WHERE routes.id = flights.route_id)').count
尽管这主要是原始SQL,但是当跳过count
时,它将返回正确的ActiveRecord::Relation
。 这允许将其用于按需加载模型,例如find_in_batches
。
很有可能可以使用Arel将其重写为更多的Rails方式,但是在这一点上,我很好奇它是否确实为您提供了正确的结果。
编辑 :
或者你可以使用
Route.joins(:ratings).joins(:deals).joins(:flights).distinct.count
它会返回正确的计数,但会产生中间的笛卡尔积,然后将其减少distinct
。 我很想知道这两种方法之间的性能差异。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.