PostGIS数据库中的几种复杂查询举例
本文包含以下内容:
- 利用索引
- 空间查询SQL示例
有效地使用PostGIS需要知道哪些空间功能可用,并确保适当的索引可用以提供良好的性能。这些示例中使用的SRID 312
仅用于演示。您应该使用spatial_ref_sys
表中列出的REAL SRID
,并使用与数据投影相匹配的REAL SRID
。如果数据未指定空间参考系统,则应仔细考虑为什么没有这样做,也许应该这样做。
如果是因为要建模的对象没有定义地理空间参考系统,例如分子的内部结构或尚未建造的游乐园的平面图,那很好。但是,如果已经计划了游乐园的位置,那么,只要确保游乐部分不会侵入已经存在的结构,就应该对该位置使用合适的平面坐标系。
即使计划在发生核大*的情况下进行火星探险以运送人类,并且您想要绘制火星行星以进行人类居住的情况,也可以使用非地球坐标系,例如火星2000并将其插入spatial_ref_sys
表中。尽管此火星坐标系是非平面的(以球面度为单位),但您可以将其与地理类型一起使用,以长度和接近度单位以米(而非度)为单位。
1. 利用索引
构造查询时,重要的是要记住,只有基于边界框的运算符(如&&)才能利用GiST空间索引。 诸如ST_Distance()
之类的函数无法使用索引来优化其操作。 例如,在大型表上,以下查询将非常慢:
SELECT the_geom
FROM geom_table
WHERE ST_Distance(the_geom, 'SRID=312;POINT(100000 200000)') < 100
该查询正在选择geom_table
中所有在点(100000,200000)的100个单位内的几何。 这会很慢,因为它正在计算表中每个点与我们指定点(即)之间的距离。 表中的每一行都进行一次ST_Distance()
计算。 我们可以通过使用单步索引加速函数ST_DWithin
减少所需的距离计算次数来避免这种情况:
SELECT the_geom
FROM geom_table
WHERE ST_DWithin(the_geom, 'SRID=312;POINT(100000 200000)', 100)
该查询选择相同的几何形状,但是它以更有效的方式执行。 假设the_geom
上有一个GiST索引,查询计划者将认识到可以在计算ST_Distance()
函数的结果之前使用该索引减少行数。 注意,在&&操作中使用的ST_MakeEnvelope
几何是一个以原始点为中心的200单位的方形框-这是我们的“查询框”。 &&运算符使用索引将结果集快速缩减为仅具有边界框与“查询框”重叠的那些几何。 假设我们的查询框比整个几何表的范围小得多,这将大大减少需要完成的距离计算的数量。
2. 空间查询SQL示例
本节中的示例将使用两个表,一个线性道路表和一个多边形市政边界表。 bc_roads
表的表定义为:
Column | Type | Description
------------+-------------------+-------------------
gid | integer | Unique ID
name | character varying | Road Name
the_geom | geometry | Location Geometry (Linestring)
边界数据bc_municipality
表的表定义为:
Column | Type | Description
-----------+-------------------+-------------------
gid | integer | Unique ID
code | integer | Unique ID
name | character varying | City / Town Name
the_geom | geometry | Location Geometry (Polygon)
所有道路的总长度是多少(以公里为单位)?
SELECT sum(ST_Length(the_geom))/1000 AS km_roads FROM bc_roads;
km_roads
------------------
70842.1243039643
(1 row)
乔治王子城有多少公顷?
SELECT
ST_Area(the_geom)/10000 AS hectares
FROM bc_municipality
WHERE name = 'PRINCE GEORGE';
hectares
------------------
32657.9103824927
(1 row)
按地区划分,全省最大的直辖市是哪个?
SELECT
name,
ST_Area(the_geom)/10000 AS hectares
FROM
bc_municipality
ORDER BY hectares DESC
LIMIT 1;
name | hectares
---------------+-----------------
TUMBLER RIDGE | 155020.02556131
(1 row)
--注意,为了回答这个查询,我们必须计算每个多边形的面积。
--如果我们经常这样做,则可以在表中添加一个Area列,这样我们就可以单独索引以提高性能。
--通过将结果按降序排列,并使用PostgreSQL的“ LIMIT”命令,我们可以轻松选择最大值,而无需使用诸如max()之类的聚合函数。
每个自治市完全包含的道路长度是多少?
--这是“空间联接”的一个示例,因为我们将来自两个表的数据(进行联接)组合在一起
--但使用空间交互条件(“包含”)作为联接条件,而不是通常的关系方法来联接:
SELECT
m.name,
sum(ST_Length(r.the_geom))/1000 as roads_km
FROM
bc_roads AS r,
bc_municipality AS m
WHERE
ST_Contains(m.the_geom, r.the_geom)
GROUP BY m.name
ORDER BY roads_km;
name | roads_km
----------------------------+------------------
SURREY | 1539.47553551242
VANCOUVER | 1450.33093486576
LANGLEY DISTRICT | 833.793392535662
BURNABY | 773.769091404338
PRINCE GEORGE | 694.37554369147
...
--该查询需要一些时间,因为表中的每条道路都汇总为最终结果
--(对于我们的特定示例表,大约为25万条道路)。
--对于较小的覆盖图(几百个记录中的数千个记录),响应速度可能非常快。
创建一张包含乔治王子市内所有道路的新表格。
--这是“叠加”的一个示例,它包含两个表并输出一个新表,该表由空间裁剪或剪切的结果组成。
---与上面展示的“空间连接”不同,此查询实际上创建了新的几何。
---覆盖层就像涡轮增压的空间连接,对于更精确的分析工作很有用:
CREATE TABLE pg_roads as
SELECT
ST_Intersection(r.the_geom, m.the_geom) AS intersection_geom,
ST_Length(r.the_geom) AS rd_orig_length,
r.*
FROM
bc_roads AS r,
bc_municipality AS m
WHERE
m.name = 'PRINCE GEORGE'
AND ST_Intersects(r.the_geom, m.the_geom);
维多利亚州“道格拉斯街”的公里长度是多少?
SELECT
sum(ST_Length(r.the_geom))/1000 AS kilometers
FROM
bc_roads r,
bc_municipality m
WHERE
r.name = 'Douglas St'
AND m.name = 'VICTORIA'
AND ST_Intersects(m.the_geom, r.the_geom);
kilometers
------------------
4.89151904172838
(1 row)
有洞的最大的自治市多边形是多少?
SELECT gid, name, ST_Area(the_geom) AS area
FROM bc_municipality
WHERE ST_NRings(the_geom) > 1
ORDER BY area DESC LIMIT 1;
gid | name | area
-----+--------------+------------------
12 | SPALLUMCHEEN | 257374619.430216
(1 row)
上一篇: Add Strings
下一篇: 数据库中的约束及创建方法?