加快OpenStreetMap PostGIS查询


12

我使用渗透模式将荷兰的OpenStreetMap数据加载到PostGIS数据库(PostgreSQL 8.3 / PostGIS 1.3.3)中。这意味着所有标签都存储在hstore字段中。除了渗透在几何字段上创建的GIST索引之外,我还在标签字段上创建了另一个GIST索引。

尝试同时使用空间约束和标签字段约束进行查询时,我发现它比我想要的要慢。这样的查询:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));

需要22秒才能返回78条记录。

该表中有大约5300万条记录。

有没有办法大大加快这一步?我听说hstore在PostgreSQL 9中的实现明显更好,升级是否有帮助?


由于这似乎是一个面向数据库的问题,我鼓励您在dba.stackexchange.com
jcolebrand 2011年

2015年更新-自从提出此问题以来,PostGIS的性能有了显着提高,因此,请考虑该问题以及PostgreSQL的升级。
Toby Speight 2015年

Answers:


5

一种方法是查询您感兴趣的标签,然后将这些记录放在新表中。然后,您只需要查询新表,而不是所有5300万条记录。如果您尝试保持数据库更新,则每次从OSM获取新数据时都可以运行此查询。


2
与其创建一个新表,不如考虑创建一个VIEW,这样就可以将“查询”实时链接到原始源数据,而无需在数据上进行字面重复。
RyanKDalton

7
视图不一定会提高查询性能,除非它是一个物化视图或同等学历(见SO问题,关于这个主题)。我不认为Postgresql 直接支持实例化视图,但是可以使用触发器来实现它们。
亚当·

2
这是我当前正在使用的解决方法。更新了渗透表之后,我重新创建了一些针对我要运行的查询进行优化的表。我只是觉得必须有更好的方法。触发器的主题引起了我的兴趣,以及如何使用它们来实现实质性的看法。@Adam Armour,您是否有机会就此分享一些见解?
mvexel

4
@mvexel看一下这个Wiki文章,其中涵盖了实例化视图的基础知识,并详细说明了如何在PostgreSQL中实现它们。
亚当·

5

您可以尝试为hstore列创建索引,

CREATE INDEX nodes_tags_idx ON nodes USING GIST(tags)

然后使用?运算符将查询限制为仅该行:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));

谢谢!我确实已经创建了该索引,只是没有使用它。它只会加速某些操作。在PostgreSQL 8.3(我正在使用)中,只有@>和??,在9.0中为@>,?,?&和?|。
mvexel

1
记录下来,使用?运算符进行查询所花的时间为48秒,而我的查询为88秒(我不知道昨天如何得到72秒,也许这一次机器在执行查询时正在做复杂的事情)。所以仍然不是我想要的性能,但是我对GIST索引如何在hstore列上进行了更深入的了解。我仍然必须使用创建物化视图的其他解决方案来获得所需的性能。
mvexel 2011年

3

st_within和_st_within函数的速度未知。&&运算符可能会有所帮助,因为它将检查bbox而不是几何

您可以尝试以下方法:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND geom && ST_SetSRID('BOX3D(4 52,5 53)'::box3d,4326);

有关更多性能提示,请访问:http : //postgis.refractions.net/docs/ch06.html


2

您查询的问题是该tags->'man_made'='surveillance'子句。这迫使Postgres扩展标签hstore,并且不允许它使用索引。如果使用@>(包含)重写此代码,则将允许使用索引。

因为查询的是矩形,所以可以使用&&代替ST_Within。这将带来很小的收益,因为ST_Within的评估并不那么复杂,并且ST_Within隐式地进行了&&检查。

额外的速度提高将是在标签上使用GIN索引而不是GIST索引。GIN索引的建立时间较长,但速度更快。

整个查询将是

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n INNER JOIN users AS u ON n.user_id = u.id WHERE tags @> hstore('man_made', 'surveillance') AND geom && ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326);

如果您知道要查询一个特定的标签,可以使用对其创建局部索引CREATE INDEX ON nodes ( tags->'man_made' ) WHERE (tags->'man_made' IS NOT NULL);

这将允许WHERE条件tags->'man_made'='surveillance'使用索引。不幸的是,该索引不能帮助@>查询,而GIN或GIST索引不能帮助tags->'foo'查询,因此您必须将查询与所拥有的索引进行匹配。


tags @>hstore()大量使用的建议改善了我的查询,谢谢。
alphabetasoup

1

试试这个代替:

SELECT n.geom,n.tags,n.tstamp,u.name FROM节点AS n INNER JOIN用户AS u ON n.user_id = u.id WHERE标签@>'man_made => surveillance':: hstore AND ST_Within(geom ,ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.