繁体   English   中英

带有Postgres的Rails 4 has_many关联:查询表A以获取实际上具有B,C和D的所有记录

[英]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答案。

使用joinsincludes将生成笛卡尔积,这将需要一些内存,并且取决于可用资源会使服务器无响应。 由于您是在计算而不是实际的记录,因此检查它们的存在应该足够了,尽管可能以更多的计算为代价:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM