活动记录子查询内部联接



我正在尝试将"原始"PostGIS SQL查询转换为Rails ActiveRecord查询。我的目标是将两个连续的 ActiveRecord 查询(每个查询需要 ~1 毫秒)转换为单个 ActiveRecord 查询(~1 毫秒)。使用下面的SQL和ActiveRecord::Base.connection.execute我能够验证时间的减少。

因此,我的直接请求是帮助我将此查询转换为 ActiveRecord 查询(以及执行它的最佳方式)。

SELECT COUNT(*)
FROM "users"
INNER JOIN (
  SELECT "centroid"
  FROM "zip_caches"
  WHERE "zip_caches"."postalcode" = '<postalcode>'
) AS "sub" ON ST_Intersects("users"."vendor_coverage", "sub"."centroid")
WHERE "users"."active" = 1;

请注意,值 <postalcode> 是此查询中唯一的变量数据。显然,这里有两种模型UserZipCacheUserZipCache没有直接关系。

当前的两步活动记录查询如下所示。

zip = ZipCache.select(:centroid).where(postalcode: '<postalcode>').limit(1).first
User.where{st_intersects(vendor_coverage, zip.centroid)}.count

声明者:我从未使用过PostGIS

首先,在您的最终请求中,您似乎错过了WHERE "users"."active" = 1;部分。

这是我要做的:

首先在用户上添加一个active范围(以实现可重用性)

scope :active, -> { User.where(active: 1) }

然后对于实际查询,您可以不执行子查询,并在 User 模型的连接中使用它,例如:

subquery = ZipCache.select(:centroid).where(postalcode: '<postalcode>')
User.active
    .joins("INNER JOIN (#{subquery.to_sql}) sub ON ST_Intersects(users.vendor_coverage, sub.centroid)")
    .count

这允许最少的原始 SQL,同时只保留一个查询。

在任何情况下,通过将记录器级别设置为调试来检查控制台/日志中的实际 sql 请求。

scuttle.io 的惊人工具非常适合转换这些类型的查询:

User.select(Arel.star.count).where(User.arel_table[:active].eq(1)).joins(
  User.arel_table.join(ZipCach.arel_table).on(
    Arel::Nodes::NamedFunction.new(
      'ST_Intersects', [
        User.arel_table[:vendor_coverage], Sub.arel_table[:centroid]
      ]
    )
  ).join_sources
)

相关内容

  • 没有找到相关文章

最新更新