2011-02-02 108 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,成规与空间索引一起使用ST_Dwithin而不是在where子句中使用距离。

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

HTH

尼克拉斯

+0

谢谢!由于某些原因,类型'地理'没有在我的PostGIS中定义。我需要的实际上是以米为单位的半径范围内的对象(存储在纬度/经度),这就是为什么我要改变mercator中的所有内容。任何其他方法呢? – Mulone 2011-02-03 10:48:50

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()谓词。根据当前文档:

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

ST_Distance()包括一个隐含的边框检查从1.3版本(这可能对索引进行),但你正在检查way一个ST_Transform,这意味着,经过该查询必须扫描所有行。可以尝试重写在其原始SRID中保留way的查询吗?喜欢ST_Distance(way,ST_Transform(...,<srid of way>))

+0

我需要的其实是对象的半径内(存储在/纬度)米,这就是为什么我要改变mercator的一切。任何其他方法呢? – Mulone 2011-02-03 10:52:11