6

「生の」PostGIS SQL クエリを Rails ActiveRecord クエリに変換しようとしています。私の目標は、2 つの連続した ActiveRecord クエリ (それぞれ約 1 ミリ秒かかる) を、(約 1 ミリ秒かかる) 単一の ActiveRecord クエリに変換することです。以下の 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>このクエリでは、値が唯一の変数データであることに注意してください。明らかに、ここには と の 2 つのモデルがUserありZipCacheます。Userとは直接関係ありませんZipCache

現在の 2 ステップの ActiveRecord クエリは次のようになります。

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

2 に答える 2

20

免責事項: 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

これにより、クエリを 1 つだけ保持しながら、生の SQL を最小限に抑えることができます。

いずれにしても、ロガー レベルをデバッグに設定して、コンソール/ログで実際の SQL 要求を確認してください。

于 2015-01-22T15:34:27.023 に答える
2

すばらしいツール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
)
于 2015-01-21T01:58:01.913 に答える