ST_Distance и «как» в Postgis - PullRequest
       11

ST_Distance и «как» в Postgis

4 голосов
/ 02 февраля 2011

Я написал этот запрос, и он работает, хотя он немного медленный:

SELECT name,
(ST_Distance( ST_Transform( way,900913 ),ST_Transform( ST_GeomFromText('POINT (-6.2222 53.307)',4326),900913 )))
FROM ga_osm_latlong_polygon 
WHERE 
( (ST_Distance( ST_Transform( way,900913 ),ST_Transform( ST_GeomFromText('POINT (-6.2222 53.307)',4326),900913 )))
<= 1000 ) 
ORDER BY
(ST_Distance( ST_Transform( way,900913 ),ST_Transform( ST_GeomFromText('POINT (-6.2222 53.307)',4326),900913 ))),
name

Я пытаюсь переписать его более элегантно, используя 'as':

SELECT name,
(ST_Distance( ST_Transform( way,900913 ),ST_Transform( ST_GeomFromText('POINT (-6.2222 53.307)',4326),900913 ))) AS d
FROM ga_osm_latlong_polygon 
WHERE ( d <= 1000 ) 
ORDER BY d, name

К сожалению, я получаю: ОШИБКА: столбец "d" не существует

Есть идеи о том, что я здесь не так делаю?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 02 февраля 2011

Hallo Mulone

По поводу вашей проблемы с псевдонимом Лютер прав.

У медленного запроса есть две причины.

Во-первых, вы преобразовываете каждую точку, чтозанимает время

Второе и, возможно, более важное значение, вы должны использовать ST_Dwithin вместе с пространственным индексом вместо использования расстояния в предложении where.

ST_Dwithin использует пространственные индексы для сортировки большого количества вычислений,

Но проекция ваших данных для выполнения этих расчетов даст вам очень неточные ответы.Почему бы не использовать вместо этого функции географии.

try:

SELECT d, name
(
  SELECT ST_Distance(a.way,b.geom) as d, a.name from 
      (SELECT way::geography, name from ga_osm_latlong_polygon) a, 
      (SELECT 'POINT(-6.2222 53.307)'::geography as geom) b 
  where ST_DWithin(a.way, b.geom, 1000)
) c
order by d, name;

Но я думаю, что я написал бы это более просто как:

  SELECT ST_Distance(a.way,b.geom) as d, a.name from 
      (SELECT way::geography, name from ga_osm_latlong_polygon) a, 
      (SELECT 'POINT(-6.2222 53.307)'::geography as geom) b 
  where ST_DWithin(a.way, b.geom, 1000)
order by ST_Distance(a.way,b.geom), name;

Но первая версия могла быбудь быстрее, потому что избегая двойного запуска ST_Distance.

Но чтобы это работало хорошо, конечно, тебе понадобится пространственный индекс. Теперь, когда я пишу его, я понимаю, что приведение к географии может быть показательным моментом для индекса.Если это так, я бы посоветовал вам сделать вместо этого столбец географии и создать соответствующий индекс.Рабочий индекс имеет значение как день и ночь.

Обновление: Или, возможно, вы можете создать индекс непосредственно с типом географии.Я не пробовал, но, возможно, стоит попробовать: вот так:

Create index idx_polygon_geog
on ga_osm_latlong_polygon
using gist(way::geography);

HTH

Никлас

0 голосов
/ 02 февраля 2011

Псевдонимы столбцов не отображаются в предложении WHERE. Вы можете переписать запрос следующим образом:

SELECT * FROM
 (
  SELECT name,
          (ST_Distance( 
            ST_Transform( way,900913 ),
            ST_Transform( ST_GeomFromText('POINT (-6.2222  53.307)',4326),900913 ))) 
      AS d
  FROM  ga_osm_latlong_polygon
 ) 

AS tmp    
WHERE ( d <= 1000 ) 
ORDER BY d, name

Кроме того, я не уверен, что PostGIS может использовать пространственный индекс в вашем предикате ST_Distance (). Согласно текущим документам:

http://postgis.refractions.net/documentation/manual-1.5/ch04.html#id2638955

ST_Distance () включает в себя неявную проверку ограничивающего прямоугольника (что можно сделать для индекса) начиная с версии 1.3 и далее, НО вы проверяете way ПОСЛЕ преобразования ST_Transform, что означает, что запрос должен сканировать все строки. Не могли бы вы попытаться переписать запрос, оставив way в исходном SRID? Нравится ST_Distance(way,ST_Transform(...,<srid of way>))?

...