現在、Rails & PostGIS を使用したアプリケーションにも取り組んでいます。:-)
複雑なクエリについては、ActiveRecords メソッドを使用する代わりに、単純な SQL を記述する方法を選択しました。これにより、管理が少し簡単になります。
あなたのものは:
SELECT
*
FROM location
WHERE
ST_DWithin(ST_GeomFromEWKB(latlong),
ST_GeomFromText('POINT(#{long} #{lat})', 4326), ?, false)
ORDER BY
ST_Distance_Sphere(ST_GeomFromEWKB(latlong),
ST_GeomFromText('POINT(#{long} #{lat})', 4326))
ちなみに、これらの座標は;-)latlon
なしで呼び出されますg
Postgres がクエリをどのように最適化するか、手動で最適化する必要があるかどうかを確認しますので、少々お待ちください。
このクエリは高速になる可能性があります (一致が多数ある場合) が、またはST_DWithin
よりもはるかに高速であるため、遅くなる可能性もあります。したがって、膨大な量のデータでテストしてください。ST_Distance
ST_Distance_Sphere
SELECT
*
FROM (
SELECT
l.*,
(
ST_DISTANCE_SPHERE(ST_GeomFromEWKB(latlong),
ST_GeomFromText('POINT(#{long} #{lat})', 4326))
) AS d
FROM location l
) x
WHERE d < ?
ORDER BY d
説明:
元のクエリは、最初に fast を使用して結果をフィルタリングし、その後、見つかったすべてのオブジェクトをST_DWithin
呼び出します。ST_Distance_Sphere
私のクエリはデータベース内のすべてのオブジェクトを計算ST_Distance_Sphere
し、その後整数比較を使用してそれらをフィルタリングします。
Rails で使用する場合は、単純に呼び出すことができます。Location.find_by_sql(...)
説明する 分析する
(私のテーブルが呼び出されmeasurement
、ポイントを含む列が呼び出されますgroundtruth
)
クエリ:
Sort (cost=341.05..341.06 rows=1 width=172) (actual time=3.676..3.731 rows=816 loops=1)
Sort Key: (_st_distance(geography(groundtruth), '0101000020E6100000EE7C3F355EF24F4019390B7BDA011940'::geography, 0::double precision, false))
Sort Method: quicksort Memory: 139kB
-> Bitmap Heap Scan on measurement m (cost=9.67..341.04 rows=1 width=172) (actual time=0.330..3.257 rows=816 loops=1)
Recheck Cond: (groundtruth && '01030000000100000005000000EE7C3F355E724D4064E42CEC6907F43FEE7C3F355E724D408C9C853DED80264077BE9F1A2F3951408C9C853DED80264077BE9F1A2F39514064E42CEC6907F43FEE7C3F355E724D4064E42CEC6907F43F'::geometry)
Filter: (('0101000000EE7C3F355EF24F4019390B7BDA011940'::geometry && st_expand(groundtruth, 5::double precision)) AND _st_dwithin(groundtruth, '0101000000EE7C3F355EF24F4019390B7BDA011940'::geometry, 5::double precision))
-> Bitmap Index Scan on groundtruth_idx (cost=0.00..9.67 rows=189 width=0) (actual time=0.186..0.186 rows=855 loops=1)
Index Cond: (groundtruth && '01030000000100000005000000EE7C3F355E724D4064E42CEC6907F43FEE7C3F355E724D408C9C853DED80264077BE9F1A2F3951408C9C853DED80264077BE9F1A2F39514064E42CEC6907F43FEE7C3F355E724D4064E42CEC6907F43F'::geometry)
Total runtime: 3.932 ms
私のクエリ:
Sort (cost=9372.84..9391.92 rows=7634 width=172) (actual time=19.256..19.312 rows=816 loops=1)
Sort Key: (st_distance(m.groundtruth, '0101000000EE7C3F355EF24F4019390B7BDA011940'::geometry))
Sort Method: quicksort Memory: 139kB
-> Seq Scan on measurement m (cost=0.00..8226.01 rows=7634 width=172) (actual time=0.040..18.863 rows=816 loops=1)
Filter: (st_distance(groundtruth, '0101000000EE7C3F355EF24F4019390B7BDA011940'::geometry) < 5::double precision)
Total runtime: 19.396 ms
ご覧のとおり、22901 から一致する行は 816 行しかありませんでした。そして、私のクエリにはさらに長い時間がかかりました。
距離を大きくすると、両方のクエリが等しく高速になります。
すべての行 (= 22901 行) が検索範囲内にある場合、私のクエリは少し速くなります: 180 対 210 ミリ秒。
したがって、おそらくあなたのソリューションにとどまるでしょう;)
1 ~ 2% のパフォーマンスが得られる可能性がある別の提案: GeomFromText を使用しないでくださいrgeo
。2 つの座標ではなく、Point オブジェクトをパラメーターとしてデータベースに直接指定するために使用できます。