Chapter 9. PostGIS常见问题解答

9.1. 我在哪里可以找到有关使用PostGIS的教程、指南和研讨会
9.2. 我的应用程序和桌面工具可以在PostGIS1.5上运行,但不能在PostGIS2.0上运行。我该怎么解决这个问题?
9.3. 当我用osm2pgsql加载OpenStreetMap数据时,我得到一个错误:失败:操作符类“GIST_GEOMETRY_OPS”不存在,访问方法“GIST”出现错误。这在PostGIS1.5中运行得很好。
9.4. 我正在运行PostgreSQL 9.0,我不能再在OpenJump、Safe FME和其他一些工具中读取/查看几何图形了?
9.5. 我试图使用PgAdmin查看我的几何图形列,但它是空白的,这是怎么回事?
9.6. 我可以存储什么类型的几何对象?
9.7. 我都糊涂了。我应该使用几何图形还是地理图形的数据存储?
9.8. 我对地理有更强烈的疑问,比如我在地理专栏中填入多大的地理区域,还能得到合理的答案。是否有一些限制,比如杆子、场地上的所有东西都必须放在一个半球内(就像SQL Server2008那样)、速度等?
9.9. 如何将地理信息系统对象插入数据库?
9.10. 如何构建空间查询?
9.11. 如何加快对大型表的空间查询?
9.12. 为什么不支持PostgreSQL R-Tree索引?
9.13. 我为什么要使用 AddGeometryColumn() 函数和所有其他OpenGIS的东西?
9.14. 查找另一个对象半径内的所有对象的最佳方法是什么?
9.15. 如何将坐标重新投影作为查询的一部分?
9.16. 我在相当大的几何体上执行了ST_AsEWKT和ST_AsText,结果返回空白字段。什么给予?
9.17. 当我执行ST_Intersects时,当我知道两个几何图形不相交时,它会告诉我它们不相交。什么给予?
9.18. 我正在发布使用PostGIS的软件,这是否意味着我的软件必须像PostGIS一样使用GPL进行许可?如果我使用PostGIS,我必须发布我所有的代码吗?
9.19. 为什么叠加运算和空间谓词的结果有时会不一致?

9.1.

我在哪里可以找到有关使用PostGIS的教程、指南和研讨会

循序渐进的教程指导工作坊 PostGIS简介 。它包括打包的数据以及使用OpenGeo Suite的简介。这可能是关于PostGIS的最好的教程。

波士顿地理信息系统也有一个 PostGIS近乎白痴的入门指南 。这一次更关注的是Windows用户。

9.2.

我的应用程序和桌面工具可以在PostGIS1.5上运行,但不能在PostGIS2.0上运行。我该怎么解决这个问题?

在PostGIS2.0中,从PostGIS代码库中删除了许多不推荐使用的函数。除了Geoserver、MapServer、QuantumGIS和OpenJump等第三方工具外,这还影响了应用程序。有几种方法可以解决这个问题。对于第三方应用程序,你可以尝试升级到这些应用程序的最新版本,这些版本中的许多问题都得到了修复。对于您自己的代码,您可以更改代码以不使用删除的函数。这些函数中的大多数是ST_UNION、ST_LENGTH等的非ST_别名,作为最后的手段,请安装整个 legacy.sql 或者仅仅是部分 legacy.sql 你需要。

这个 legacy.sql 文件与postgis.sql位于同一文件夹中。您可以在安装了postgis.sql和spatial_ref_sys.sql之后安装该文件,以恢复我们删除的所有200多个旧函数。

9.3.

当我用osm2pgsql加载OpenStreetMap数据时,我得到一个错误:失败:操作符类“GIST_GEOMETRY_OPS”不存在,访问方法“GIST”出现错误。这在PostGIS1.5中运行得很好。

在PostGIS 2中,默认几何运算符类GIST_GEOMETRY_OPS被更改为GIST_GEOMETRY_OPS_2d,并且完全删除了GIST_GEOMETRY_OPS。之所以这样做,是因为PostGIS2还引入了支持3D的ND空间索引,而旧名称被认为令人困惑和用词不当。

一些较旧的应用程序作为该过程的一部分创建表和索引,它们显式引用了运算符类名称。如果需要默认的2D索引,则不需要执行此操作。因此,如果您管理说好,则将索引创建从以下位置更改:

不好的:

CREATE INDEX idx_my_table_geom ON my_table USING gist(geom gist_geometry_ops);

转到好:

CREATE INDEX idx_my_table_geom ON my_table USING gist(geom);

唯一需要指定运算符类的情况是需要3D空间索引,如下所示:

CREATE INDEX idx_my_super3d_geom ON my_super3d USING gist(geom gist_geometry_ops_nd);

如果您不幸地陷入了编译代码的困境,您不能更改硬编码了旧的gist_geometryops的代码,那么您可以使用 legacy_gist.sql 打包在PostGIS 2.0.2+中。但是,如果您使用此修复程序,则建议您在以后删除索引并在不使用运算符类的情况下重新创建它。这将为您在未来需要再次升级时省去悲伤。

9.4.

我正在运行PostgreSQL 9.0,我不能再在OpenJump、Safe FME和其他一些工具中读取/查看几何图形了?

在PostgreSQL 9.0+中,byteA数据的默认编码已更改为十六进制,较旧的JDBC驱动程序仍采用转义格式。这影响了一些应用程序,如使用旧版JDBC驱动程序的Java应用程序或使用旧版npgsql驱动程序的.NET应用程序,这些应用程序期望ST_AsBinary的旧行为。有两种方法可以让这一点再次发挥作用。

您可以将JDBC驱动程序升级到最新的PostgreSQL 9.0版本,您可以从 http://jdbc.postgresql.org/download.html

如果您运行的是.NET应用程序,则可以使用Npgsql 2.0.11或更高版本,可从下载 http://pgfoundry.org/frs/?group_id=1000140 并且如上所述 Francisco Figueiredo的NpgSQL 2.0.11发布博客条目

如果不能升级您的PostgreSQL驱动程序,则可以通过以下更改将默认行为设置回旧行为:

ALTER DATABASE mypostgisdb SET bytea_output='escape';

9.5.

我试图使用PgAdmin查看我的几何图形列,但它是空白的,这是怎么回事?

对于大型几何图形,pgAdmin不会显示任何内容。验证几何图形列中是否有数据的最佳方法是?

-- this should return no records if all your geom fields are filled in
SELECT somefield FROM mytable WHERE geom IS NULL;
-- To tell just how large your geometry is do a query of the form
--which will tell you the most number of points you have in any of your geometry columns
SELECT MAX(ST_NPoints(geom)) FROM sometable;

9.6.

我可以存储什么类型的几何对象?

可以存储点几何图形、线串几何图形、多边形几何图形、多点几何图形、多重线串几何图形、多重多边形几何图形和几何集合几何图形。在PostGIS 2.0及更高版本中,您还可以将三角网和多面体曲面存储为基本几何类型。它们以Open GIS知名文本格式(扩展名为Z、M和ZM)指定。目前支持三种数据类型。标准OGC几何数据类型,使用平面坐标系进行测量;地理数据类型,使用大地坐标系,在球体或椭球体上进行计算。PostGIS空间类型家族的最新成员是用于存储和分析栅格数据的栅格。RASTER有自己的常见问题解答。参考 Chapter 13, PostGIS栅格常见问题解答Chapter 12, 栅格参考 了解更多详细信息。

9.7.

我都糊涂了。我应该使用几何图形还是地理图形的数据存储?

简而言之:地理是一种较新的数据类型,支持长距离测量,但其上的大多数计算比几何上的计算慢。如果你使用地理学,你不需要学习太多关于平面坐标系的知识。如果你所关心的只是测量距离和长度,并且你有来自世界各地的数据,那么地理通常是最好的。几何数据类型是一种较旧的数据类型,具有更多支持它的函数,享有来自第三方工具的更大支持,并且对它的操作通常更快--对于更大的几何图形,有时快10倍。如果您对空间参考系非常熟悉,或者您正在处理的本地化数据中所有数据都可以放在一个 空间参考系(SRID) ,或者需要做大量的空间处理。注意:在这两种类型之间进行一次性转换以获得各自的好处相当容易。参考 Section 15.11, “PostGIS Function Support Matrix” 查看当前支持的内容和不支持的内容。

长长的答案:请参阅我们在 Section 4.3.3, “何时使用地理数据类型” 函数类型矩阵

9.8.

我对地理有更强烈的疑问,比如我在地理专栏中填入多大的地理区域,还能得到合理的答案。是否有一些限制,比如杆子、场地上的所有东西都必须放在一个半球内(就像SQL Server2008那样)、速度等?

你的问题太深刻和复杂,在这一节中无法得到充分的回答。请参阅我们的 Section 4.3.4, “地理高级常见问题解答”

9.9.

如何将地理信息系统对象插入数据库?

首先,您需要创建一个表,其中包含类型为“GEOMETRY”或“GEOGRAPHY”的列,以保存您的GIS数据。存储地理类型数据与存储几何图形略有不同。参考 Section 4.3, “地理数据类型” 获取有关存储地理位置的详细信息。

对于几何图形:使用以下命令连接到数据库 psql 并尝试使用以下SQL:

CREATE TABLE gtest (id serial primary key, name varchar(20), geom geometry(LINESTRING));

如果几何图形列定义失败,则您可能尚未将PostGIS函数和对象加载到此数据库中,或者正在使用早于2.0版本的PostGIS。请参阅 Section 2.2, “从源代码编译和安装”

然后,可以使用SQL INSERT语句将几何图形插入到表中。地理信息系统对象本身使用OpenGIS Consortium“知名文本”格式进行格式化:

INSERT INTO gtest (ID, NAME, GEOM)
VALUES (
  1,
  'First Geometry',
  ST_GeomFromText('LINESTRING(2 3,4 5,6 5,7 8)')
);

有关其他GIS对象的详细信息,请参阅 对象引用

要在表格中查看您的GIS数据,请执行以下操作:

SELECT id, name, ST_AsText(geom) AS geom FROM gtest;

返回值应如下所示:

id | name           | geom
----+----------------+-----------------------------
  1 | First Geometry | LINESTRING(2 3,4 5,6 5,7 8)
(1 row)

9.10.

如何构建空间查询?

构造任何其他数据库查询的方式与构造返回值、函数和布尔测试的SQL组合的方式相同。

对于空间查询,在构建查询时有两个重要的问题需要记住:是否有可以使用的空间索引;以及,您是否在大量几何图形上进行昂贵的计算。

通常,您需要使用“Intersects运算符”( & & ),它测试特征的边界框是否相交。其原因是 & & 运算符之所以有用,是因为如果空间索引可用来加速测试,则 & & 操作员将利用这一点。这可以使查询变得更快。

您还将使用空间函数,如Distance()、ST_Intersects()、ST_CONTAINS()和ST_WITHING()等,以缩小搜索结果的范围。大多数空间查询既包括索引测试,也包括空间函数测试。索引测试用于将返回元组的数量限制为仅 威力 符合相关条件。然后使用空间函数来准确地测试条件。

SELECT id, geom
FROM thetable
WHERE
  ST_Contains(geom,'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');

9.11.

如何加快对大型表的空间查询?

对大型表的快速查询是 《理由》 空间数据库(以及事务支持),因此拥有良好的索引是很重要的。

在表上构建空间索引 geometry 列中使用“CREATE INDEX”函数,如下所示:

CREATE INDEX [indexname] ON [tablename] USING GIST ( [geometrycolumn] );

“Using GIST”选项告诉服务器使用GIST(通用搜索树)索引。

[Note]

假设GIST指数是有损的。Lossy索引使用代理对象(在空间情况下是边界框)来构建索引。

您还应该确保PostgreSQL查询规划器拥有关于您的索引的足够信息,以便合理地决定何时使用它。要做到这一点,你必须在你的几何表上“收集统计数据”。

对于PostgreSQL 8.0.x和更高版本,只需运行 VACUUM ANALYZE 指挥部。

对于PostgreSQL 7.4.x和更低版本,请运行 SELECT UPDATE_GEOMETRY_STATS() 指挥部。

9.12.

为什么不支持PostgreSQL R-Tree索引?

早期版本的PostGIS使用PostgreSQL R-Tree索引。然而,从版本0.6开始,PostgreSQL R-树已经完全被丢弃,并且空间索引提供了R-Tree-over-gist方案。

我们的测试表明,原生R-Tree和GIST的搜索速度是相当的。原生PostgreSQL R树有两个限制,这使得它们不适合与GIS功能一起使用(请注意,这些限制是由于当前的PostgreSQL原生R树实现,而不是一般的R树概念):

  • PostgreSQL中的R-Tree索引无法处理大小超过8K的要素。Gist索引可以使用“有损”技巧,用边界框替换要素本身。

  • PostgreSQL中的R-Tree索引不是“空安全的”,因此在包含空几何的几何列上构建索引将失败。

9.13.

我为什么要使用 AddGeometryColumn() 函数和所有其他OpenGIS的东西?

如果您不想使用OpenGIS支持功能,则不必使用。只需像在旧版本中一样创建表,在CREATE语句中定义几何列。所有几何的SRID都将为-1,OpenGIS元数据表将 要正确填写。但是,这会导致大多数基于PostGIS的应用程序失败,因此通常建议您使用 AddGeometryColumn() 要创建几何表,请执行以下操作。

MapServer是一个利用 geometry_columns 元数据。具体地说,MapServer可以使用几何图形列的SRID将要素即时重新投影到正确的地图投影中。

9.14.

查找另一个对象半径内的所有对象的最佳方法是什么?

要最有效地使用数据库,最好执行RADIUS查询,将RADIUS测试与边界框测试相结合:边界框测试使用空间索引,从而快速访问数据子集,然后对其应用RADIUS测试。

这个 ST_DWithin(geometry, geometry, distance) 函数是执行索引距离搜索的一种便捷方法。它的工作原理是创建一个足够大的搜索矩形来包围距离半径,然后对索引的结果子集执行精确的距离搜索。

例如,要查找点为100米(1000 1000)的所有对象,可以使用以下查询:

SELECT * FROM geotable
WHERE ST_DWithin(geocolumn, 'POINT(1000 1000)', 100.0);

9.15.

如何将坐标重新投影作为查询的一部分?

要执行重投影,必须在SPATIAL_REF_SYS表中定义源和目标坐标系,并且要重投影的几何必须已经设置了SRID。一旦完成,重新投影就像引用所需的目的地SRID一样简单。下面是一个经度为NAD 83的几何图形。仅当geom的sRID不是-1(不是未定义的空间参考)时,以下选项才有效

SELECT ST_Transform(geom,4269) FROM geotable;

9.16.

我在相当大的几何体上执行了ST_AsEWKT和ST_AsText,结果返回空白字段。什么给予?

您可能正在使用PgAdmin或其他不能输出大文本的工具。如果您的几何体足够大,它将在这些工具中显示为空白。如果您确实需要在WKT中查看或输出它,请使用PSQL。

--To check number of geometries are really blank
                                SELECT count(gid) FROM geotable WHERE geom IS NULL;

9.17.

当我执行ST_Intersects时,当我知道两个几何图形不相交时,它会告诉我它们不相交。什么给予?

这通常发生在两种常见的情况下。您的几何无效--检查 ST_IsValid 或者您假设它们是相交的,因为ST_AsText截断了数字,并且在它没有显示给您之后有很多小数。

9.18.

我正在发布使用PostGIS的软件,这是否意味着我的软件必须像PostGIS一样使用GPL进行许可?如果我使用PostGIS,我必须发布我所有的代码吗?

几乎可以肯定的是,不会。例如,考虑在Linux上运行的Oracle数据库。Linux是GPL,Oracle不是:运行在Linux上的Oracle必须使用GPL分发吗?不是的。同样,您的软件可以随心所欲地使用PostgreSQL/PostGIS数据库,并且可以使用您喜欢的任何许可证。

唯一的例外是您对PostGIS源代码进行了更改,并且 已分发您更改的版本 对PostGIS的研究。在这种情况下,您必须共享更改后的PostGIS的代码(但不共享在其上运行的应用程序的代码)。即使在这种有限的情况下,您仍然只需要将源代码分发给您向其分发二进制文件的人。GPL并不要求您 出版 您的源代码,只是您将其与您提供二进制文件的人共享。

即使您将PostGIS与可选的启用CGAL的函数结合使用,上述情况仍然成立。CGAL的一部分是GPL,但所有的PostGIS都是GPL:使用CGAL并不会使PostGIS比开始时更具GPL。

9.19.

为什么叠加运算和空间谓词的结果有时会不一致?

这通常是作为特定案例来表示的,例如

  • 何以 ST_Contains( A, ST_Intersection(A, B) ) 假的?

  • 何以 ST_Contains( ST_Union(A, B), A ) ) 假的?

  • 何以 ST_Union( A, ST_Difference(A, B) ) 不等于A?

  • 为什么 ST_Difference(A, B) 与…的内部相交 B

原因是,PostGIS表示几何图形并使用有限精度浮点数执行运算。这提供了使用实数进行计算的错觉--但这只是一种错觉。不可避免地会出现微小的误差,这会导致不同操作的结果略有不一致。

此外,PostGIS操作包含错误预防代码,该代码可能会对输入几何进行微小扰动,以防止出现健壮性错误。这些微小的改动也可能产生不完全一致的计算结果。

结果之间的差异应该总是非常小的。但在比较覆盖结果时,查询不应依赖于精确的一致性。相反,可以考虑在几何比较中使用基于面积或距离的公差。