2011-02-02 2 views
4

Я написал этот запрос, и он работает, хотя это немного медленно:ST_Distance и «как» в PostGIS

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 

Я пытаюсь переписать его в более изящным способом, используя «как» :

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

Hallo Mulone

О вашей проблеме псевдонима, Лютер прав.

О запросе, являющемся медленным, имеет две причины.

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

Второй и, вероятно, больше Importand, youshould использовать ST_Dwithin вместе с пространственным индексом вместо расстояния в ИНЕКЕ.

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

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

попробовать:

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); 

НТН

Никлас

+0

Спасибо! по какой-то причине тип «география» не определен в моей PostGIS. Мне нужны на самом деле объекты (хранятся в lat/lon) в радиусе в метрах, поэтому я все преобразую в меркаторе. Любой другой подход для этого? – Mulone

0

Атрибуты столбцов не видны в предложении 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() предикат. В соответствии с текущим Docs:

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>))?

+0

Что мне нужно на самом деле объекты (хранится в широта/долгота) в радиусе в метрах, вот почему я превращаю все в меркатора. Любой другой подход для этого? – Mulone

Смежные вопросы