PostGIS官方入门教程-英译汉随笔

官方教程地址:https://postgis.net/workshops/postgis-intro/index.html

2.简介

2.1 什么是空间数据库

PostGIS是一种空间数据库,Oracle Spatial 和Sql Server(2008及以后版本)也是空间数据库。但是,是什么让普通数据库变成空间数据库?
简短回答就是:
空间数据库能像存储和操作普通对象一样操作空间对象。
下面简短说明空间数据库的演进,然后复习一下用空间数据库组织空间数据的3个重要的概念,数据类型(Spatial data types)、索引(spatial indexing)、函数(Spatial functions)。
1.空间数据类型指图形,比如点、线、面;
2.多维空间索引用来高效的处理空间操作;
3.空间函数支持用sql的方式来查询空间属性和空间关系。
对于优化性能和分析,三者组合起来形成一个复杂的结构。

4.创建空间数据库

新建数据库
添加postgis扩展create EXTENSION postgis;
查看postgis版本信息select postgis_full_version();,查询结果:
"POSTGIS="3.0.1 3.0.1" [EXTENSION] PGSQL="110" GEOS="3.8.0-CAPI-1.13.1 " PROJ="Rel. 5.2.0, September 15th, 2018" LIBXML="2.9.9" LIBJSON="0.12" LIBPROTOBUF="1.2.1" WAGYU="0.4.3 (Internal)""

5.加载空间数据

使用shp2pgsql程序,添加数据库连接,添加待导入文件,配置选项后即可导入;
查看空间参考信息:
SELECT srtext FROM spatial_ref_sys WHERE srid = 26918;

7.简单的sql

SELECT avg(char_length(name)), stddev(char_length(name))  FROM nyc_neighborhoods  WHERE boroname = 'Brooklyn';
SELECT boroname, avg(char_length(name)), stddev(char_length(name))  FROM nyc_neighborhoods  GROUP BY boroname;

8.简单的sql练习

SELECT Sum(popn_total) AS population  FROM nyc_census_blocks;
SELECT Sum(popn_total) AS population  FROM nyc_census_blocks  WHERE boroname = 'The Bronx';
SELECT  boroname,  100 * Sum(popn_white)/Sum(popn_total) AS white_pct FROM nyc_census_blocks GROUP BY boroname;

9. 几何

9.1简介

CREATE TABLE geometries (name varchar, geom geometry);

INSERT INTO geometries VALUES  ('Point', 'POINT(0 0)'),  ('Linestring', 'LINESTRING(0 0, 1 1, 2 1, 2 2)'),  ('Polygon', 'POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'),  ('PolygonWithHole', 'POLYGON((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1))'),  ('Collection', 'GEOMETRYCOLLECTION(POINT(2 0),POLYGON((0 0, 1 0, 1 , 0 1, 0 0)))');

SELECT name, ST_AsText(geom) FROM geometries;

9.2元数据表

空间数据库种定义的空间参考系统spatial_ref_sys
描述所有要素类的几何字段信息geometry_columns
SELECT * FROM geometry_columns;

9.3表达真实世界的对象

-ST_GeometryType(geometry) 返回几何类型;
-ST_NDims(geometry)返回几何维度
-ST_SRID(geometry)返回几何的空间参考id

SELECT name, ST_GeometryType(geom), ST_NDims(geom), ST_SRID(geom)  FROM geometries;

points

SELECT ST_AsText(geom) FROM geometries WHERE name = 'Point';返回文本形式表达的点POINT(0 0)
SELECT ST_X(geom), ST_Y(geom) FROM geometries WHERE name = 'Point';分别返回x\y坐标值

9.3.2linestring

closed:首尾点相同的线
simple:线没有自身相交或者相邻接的情况(closed时,末尾点除外);
一个线可以是closed和simple;
返回线的文字表达:SELECT ST_AsText(geom) FROM geometries WHERE name = 'Linestring';LINESTRING(0 0, 1 1, 2 1, 2 2)
常用函数:
-ST_Length(geometry)返回线的长度
-ST_StartPoint(geometry) 返回起点
-ST_EndPoint(geometry) 返回终点
-ST_NPoints(geometry) 返回点的个数

polygons


SELECT ST_AsText(geom) FROM geometries WHERE name LIKE 'Polygon%';
POLYGON((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1))
常用函数
-ST_Area(geometry) returns the area of the polygons
-ST_NRings(geometry) returns the number of rings (usually 1, more of there are holes)
-ST_ExteriorRing(geometry) returns the outer ring as a linestring
-ST_InteriorRingN(geometry,n) returns a specified interior ring as a linestring
-ST_Perimeter(geometry) returns the length of all the rings

9.3.4集合

-MultiPoint, a collection of points
-MultiLineString, a collection of linestrings
-MultiPolygon, a collection of polygons
-GeometryCollection, a heterogeneous collection of any geometry (including other collections)由任何几何组成的混杂的集合,包括集合
-ST_NumGeometries(geometry) returns the number of parts in the collection
-ST_GeometryN(geometry,n) returns the specified part
-ST_Area(geometry) returns the total area of all polygonal parts
-ST_Length(geometry) returns the total length of all linear parts

9.4 几何输入和输出

postgis支持的几类格式

  • Well-known text (WKT)
    • ST_GeomFromText(text, srid) returns geometry
    • ST_AsText(geometry) returns text
    • ST_AsEWKT(geometry) returns text
  • Well-known binary (WKB)
    • ST_GeomFromWKB(bytea) returns geometry
    • ST_AsBinary(geometry) returns bytea
    • ST_AsEWKB(geometry) returns bytea
  • Geographic Mark-up Language (GML)
    • ST_GeomFromGML(text) returns geometry
    • ST_AsGML(geometry) returns text
  • Keyhole Mark-up Language (KML)
    • ST_GeomFromKML(text) returns geometry
    • ST_AsKML(geometry) returns text
  • GeoJSON
    • ST_AsGeoJSON(geometry) returns text
  • Scalable Vector Graphics (SVG)
    • ST_AsSVG(geometry) returns text
SELECT encode( ST_AsBinary(ST_GeometryFromText('LINESTRING(0 0,1 0)')),  'hex');
SELECT ST_AsText(ST_GeometryFromText('LINESTRING(0 0 0,1 0 0,1 1 2)'));
SELECT ST_AsGeoJSON(ST_GeomFromGML('<gml:Point><gml:coordinates>1,1</gml:coordinates></gml:Point>'));

从文本转换

采用 oldata::newtype的简写形式进行格式转化,例如:SELECT 0.9::text;将double转化为文本;SELECT 'POINT(0 0)'::geometry;wkt转化为几何;SELECT 'SRID=4326;POINT(0 0)'::geometry;带空间参考

11空间关系

空间数据库的强大不仅在于可以存储几何,更体现在能比对几何之间的空间位置关系。

11.1

ST_Equals(geometry A, geometry B) :测试两个几何是否空间相等。如果两个几何拥有完全一样的坐标值,则返回TRUE
支持如下几何类型之间进行比较,

11.2 ST_Intersects, ST_Disjoint, ST_Crosses and ST_Overlaps

ST_Intersects, ST_Crosses, and ST_Overlaps 检测几何是否存在相交关系。其中Intersects为广义的相交,包含了Cross和Overlap2中情况,具体入下:
ST_Intersects(geometry A, geometry B) :如果2个几何有任何公共部分,则返回true;
ST_Disjoint,如果2个几何是相离的,则他们不相交,事实上,因为相交操作可基于空间索引进行,所以监测不相交比检测相离更高效,但可以得到相同的结果。

Cross

image.png

当2个几何的相交部分的几何维度比这2个几何中的最高维度低一个维度时,则称这2个几何为Cross关系。

Overlap


用于比较2个同维度的几何,当2个同维度的几何的交集与该2个几何都不相同,但是维度相同时,称为Overlap。
ex:找到与地铁站'Broad St'相交的社区名字

SELECT name, ST_AsText(geom)
FROM nyc_subway_stations
WHERE name = 'Broad St';
return:POINT(583571 4506714)
SELECT name, boroname
FROM nyc_neighborhoods
WHERE ST_Intersects(geom, ST_GeomFromText('POINT(583571 4506714)',26918));

ST_Touches

ST_Touches检测两个几何是否拥有共同边界,但不存在内部相交关系。


ST_Within and ST_Contains

ST_Within and ST_Contains 检测一个几何是否完全在另一个几何内。


11.5 ST_Distance and ST_DWithin

GIS中最常见的问题“就是找到距离一个东西X距离以内的所有东西”
ST_Distance(geometry A, geometry B)以float形式返回两个几何之间的最短距离
SELECT ST_Distance( ST_GeometryFromText('POINT(0 5)'), ST_GeometryFromText('LINESTRING(-2 2, 2 2)'));
为了测试物体是否位于另一物体一定距离内,ST_DWithin函数提供了一个用索引加速了的方法,,比如这条路两边500米缓冲区内有多少条路,不用做缓冲区,使用该方法进行检测即可。


查询记录点(583571 4506714)10米以内的街道;
SELECT name FROM nyc_streets WHERE ST_DWithin( geom, ST_GeomFromText('POINT(583571 4506714)',26918), 10 );
return: Wall St Broad St Nassau St

13 空间连接

空间连接是空间数据库的最基本的功能。
上一节内容中,先选择一个地铁站的点坐标,再使用空间关系操作查询该点附近的街区,使用空间连接则只需一部即可完成该操作:
SELECT subways.name AS subway_name, neighborhoods.name AS neighborhood_name, neighborhoods.boroname AS borough FROM nyc_neighborhoods AS neighborhoods JOIN nyc_subway_stations AS subways ON ST_Contains(neighborhoods.geom, subways.geom) WHERE subways.name = 'Broad St';
任何返回true/false的空间关系函数都可以用来创建空间连接,最常用的包括:ST_Intersects, ST_Contains, and ST_DWithin。

13.1 Join and Summarize

JoinGroup by的组合形成了GIS系统中最常见的分析。
例如:曼哈顿街区的人口和人种构成情况如何?

SELECT
  neighborhoods.name AS neighborhood_name,
  Sum(census.popn_total) AS population,
  100.0 * Sum(census.popn_white) / Sum(census.popn_total) AS white_pct,
  100.0 * Sum(census.popn_black) / Sum(census.popn_total) AS black_pct
FROM nyc_neighborhoods AS neighborhoods
JOIN nyc_census_blocks AS census
ON ST_Intersects(neighborhoods.geom, census.geom)
WHERE neighborhoods.boroname = 'Manhattan'
GROUP BY neighborhoods.name
ORDER BY white_pct DESC;

如何做到的呢?理论(实际上数据库系统对执行顺序做了优化)上做了以下处理:

  1. JOIN语句创建了一个同时包含了neighborhoods表和census表的所有字段的虚拟表;
  2. where语句对虚拟表进行筛选,只保留Manhattan的记录;
  3. 剩下的记录按照街区名字进行分组汇总,使用聚合函数sum()对人口进行求和,
  4. 再经过一点小小的计算和格式化,得出结果。


13.2 高级连接

SELECT
  lines.route,
  100.0 * Sum(popn_white) / Sum(popn_total) AS white_pct,
  100.0 * Sum(popn_black) / Sum(popn_total) AS black_pct,
  Sum(popn_total) AS popn_total
FROM nyc_census_blocks AS census
JOIN nyc_subway_stations AS subways
ON ST_DWithin(census.geom, subways.geom, 200)
JOIN subway_lines AS lines
ON strpos(subways.routes, lines.route) > 0
GROUP BY lines.route
ORDER BY black_pct DESC;

计算每条线路服务的人口数量及结构分布情况

15.空间索引

再次强调空间索引是空间数据库的三个关键要是之一。空间索引使得数据库操作大规模数据集合变成可能。
当我们加载nyc_census_blocks表时,pgShapeLoader自动创建了名为nyc_census_blocks_geom_idx的索引。为了展示索引的重要性,我们做个测试(thinkpad t480 i5 16G ),首先删除索引DROP INDEX nyc_census_blocks_geom_idx;执行如下sqlSELECT blocks.blkid FROM nyc_census_blocks blocks JOIN nyc_subway_stations subways ON ST_Contains(blocks.geom, subways.geom) WHERE subways.name = 'Broad St';查询结果为一条记录,时间为64msec;


现在再次添加索引CREATE INDEX nyc_census_blocks_geom_idx ON nyc_census_blocks USING GIST (geom);执行同样的查询,49msecd,结果不是很明显,可能表的总记录数比较少的原因吧。

15.1 空间索引是如何工作的

标准数据库的索引是给索引字段的值创建一个层次树。空间索引有一点点不同,它不索引集合要素本身,取而代之的是索引集合要素的bounding boxes(最小外接矩形)。如图:


与红色星星相交的只有一条线(如图1),但对于外接矩形而言,2条线(红色和蓝色)的外接矩形都与星星的外接矩形相交。
数据库在检索“哪条线与星星相交”时,首先检索“哪个外接矩形与星星的外接矩形相交”,可通过索引快速检索出结果。然后用检索出来的外接矩形框对应的线再与星星做空间关系检测,只需检测2次,其中红色为TURE,蓝色为Flase,绿色线不参与检索。在没有空间索引的情况下,线表中的每一条线都需要需星星进行检测,才能得到结果。
对于大规模的数据表,首先通过近似的外接矩形索引初次检测,基于初次检测结果再进行精确检测的两部操作方法(“tow pass”),可根本上大大大减少查询需要的计算量。
PostGIS和OracleSpatial共享同样的R-Tree空间索引。R-tree将数据切分为矩形,子矩形,子子矩形等。是一个自动处理可变的数据密度和对象大小的自协调的索引结构。

15.2 Index-Only Queries

PostGIS中大多数函数(ST_Contains, ST_Intersects, ST_DWithin, etc)都自动包含了索引过滤,但是有些则没有(e.g., ST_Relate)。
使用&&操作符来执行外接矩形框的查询。例如:

SELECT Sum(popn_total)
FROM nyc_neighborhoods neighborhoods
JOIN nyc_census_blocks blocks
ON neighborhoods.geom && blocks.geom
WHERE neighborhoods.name = 'West Village';

return 49821条记录。
使用精确空间查询:

SELECT Sum(popn_total)
FROM nyc_neighborhoods neighborhoods
JOIN nyc_census_blocks blocks
ON ST_Intersects(neighborhoods.geom, blocks.geom)
WHERE neighborhoods.name = 'West Village';

return 26718条记录。使用外接矩形查询结果当然比精确查询多,上一条查询结果理解为外接矩形与外接矩形相交的所有记录。

15.3Analyzing

PostGIS的查询分析器智能选择执行查询时是否使用索引。与直觉相反的时,使用索引并不总是最快的:如果查询结果时返回表里的所有记录,通过索引来检索每一条记录就比直接顺序读取记录要慢很多。
为了分辨出当前处理的是哪种情况(只读取一点记录还是读取大部分记录),PostgreSQL在持续统计每一个索引表列的数据量情况。通常情况下,PostgreSQL定期收集统计信息,然后,当你短时间内明显的改变了表的数据内容时,统计信息的更新可能就会有延迟(not be up-to-date)。
为了使统计信息与表内容相匹配,在大量的插入或者删除数据后,可以运行ANALYZE命令来触发更新。ANALYZE nyc_census_blocks;

15.4.Vacuuming

值得强调的是,仅仅创建索引不足以让PostgreSql高效的使用它。
新建索引或者大数据量的UPDATEs、INSERTs、DELETEs操作后都需要进行Vacuuming。VACUUM命令让PostgreSQL回收更新或者删除后留在表页上的未利用的空间。
Vacuuming是如此重要,所以PostgresSQL提供了autovacuuming选项。
默认的autovacuuming会定期执行,对于高度事务性数据库,等待autovacuuming是不明智的,在添加索引、大量加载数据或者大量的数据更新后,应该手动执行VACUUMM
Vacuuming and analyzing可以根据需要分别执行。VACUUM不会更新数据库的统计信息,同样的ANALYZE也不会回收未利用的空间。这2个命令的执行对象可以是数据库、表和列。可同时执行。
VACUUM ANALYZE nyc_census_blocks;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345