開放地理空間聯盟 (OGC) 開發了簡單要素存取 (SFA) 標準,以提供地理空間資料的模型。它定義了基本的空間類型幾何 (Geometry),以及操作和轉換幾何值以執行空間分析任務的操作。PostGIS 將 OGC 幾何模型實作為 PostgreSQL 資料類型geometry 和geography。
幾何是一個抽象類型。幾何值屬於其具體子類型之一,這些子類型代表幾何形狀的各種種類和維度。這些子類型包括原子類型 Point、LineString、LinearRing 和 Polygon,以及集合類型 MultiPoint、MultiLineString、MultiPolygon 和 GeometryCollection。簡單要素存取 - 第 1 部分:通用架構 v1.2.1 為結構 PolyhedralSurface、Triangle 和 TIN 新增了子類型。
幾何在二維笛卡爾平面中模擬形狀。PolyhedralSurface、Triangle 和 TIN 類型也可以表示三維空間中的形狀。形狀的大小和位置由其座標指定。每個座標都有一個 X 和 Y 縱座標值,決定其在平面中的位置。形狀由點或線段構成,點由單一座標指定,線段由兩個座標指定。
座標可以包含可選的 Z 和 M 縱座標值。Z 縱座標通常用於表示高程。M 縱座標包含測量值,可以表示時間或距離。如果幾何值中存在 Z 或 M 值,則必須為幾何中的每個點定義它們。如果幾何具有 Z 或 M 縱座標,則座標維度為 3D;如果同時具有 Z 和 M,則座標維度為 4D。
幾何值與空間參考系統相關聯,指示嵌入它的座標系統。空間參考系統由幾何 SRID 編號識別。X 和 Y 軸的單位由空間參考系統決定。在平面參考系統中,X 和 Y 座標通常表示東距和北距,而在大地系統中,它們表示經度和緯度。SRID 0 表示一個無限的笛卡爾平面,其軸未指定任何單位。請參閱第 4.5 節,「空間參考系統」。
幾何維度是幾何類型的一個屬性。點類型具有維度 0,線性類型具有維度 1,多邊形類型具有維度 2。集合具有最大元素維度的維度。
幾何值可以是空的。空值不包含頂點 (對於原子幾何類型) 或不包含元素 (對於集合)。
幾何值的一個重要屬性是它們的空間範圍或邊界框,OGC 模型稱之為包絡。這是封閉幾何座標的 2 或 3 維框。這是以座標空間表示幾何範圍並檢查兩個幾何是否交互的一種有效方法。
幾何模型允許評估拓撲空間關係,如第 5.1.1 節,「維度擴展 9-交集模型」中所述。為了支援這一點,為每個幾何類型定義了內部、邊界和外部的概念。幾何在拓撲上是封閉的,因此它們始終包含其邊界。邊界是幾何維度小於幾何本身維度的一個幾何。
OGC 幾何模型為每個幾何類型定義了有效性規則。這些規則確保幾何值表示真實的情況 (例如,可以指定一個孔洞位於外殼之外的多邊形,但這在幾何上沒有意義,因此是無效的)。PostGIS 也允許儲存和操作無效的幾何值。如果需要,這允許偵測和修復它們。請參閱第 4.4 節,「幾何驗證」。
點是一個 0 維幾何,表示座標空間中的單個位置。
POINT (1 2) POINT Z (1 2 3) POINT ZM (1 2 3 4)
線串是由連續線段序列形成的 1 維線。每個線段由兩個點定義,一個線段的終點形成下一個線段的起點。一個 OGC 有效線串具有零個或兩個或更多個點,但 PostGIS 也允許單點線串。線串可能會自相交。如果起點和終點相同,則線串是封閉的。如果線串不自相交,則它是簡單的。
LINESTRING (1 2, 3 4, 5 6)
線環是一個既封閉又簡單的線串。第一個點和最後一個點必須相等,並且該線不能自相交。
LINEARRING (0 0 0, 4 0 0, 4 4 0, 0 4 0, 0 0 0)
多邊形是一個 2 維平面區域,由外部邊界 (外殼) 和零個或多個內部邊界 (孔洞) 分隔。每個邊界都是一個線環。
POLYGON ((0 0 0,4 0 0,4 4 0,0 4 0,0 0 0),(1 1 0,2 1 0,2 2 0,1 2 0,1 1 0))
多點是一個點的集合。
MULTIPOINT ( (0 0), (1 2) )
多線串是線串的集合。如果其每個元素都是封閉的,則多線串是封閉的。
MULTILINESTRING ( (0 0,1 1,1 2), (2 3,3 2,5 4) )
多多邊形是一個不重疊、不相鄰的多邊形集合。集合中的多邊形只能在有限數量的點上接觸。
MULTIPOLYGON (((1 5, 5 5, 5 1, 1 1, 1 5)), ((6 5, 9 1, 6 1, 6 5)))
幾何集合是幾何的異質 (混合) 集合。
GEOMETRYCOLLECTION ( POINT(2 3), LINESTRING(2 3, 3 4))
多面體表面是共享一些邊的連續的貼片或面的集合。每個貼片都是一個平面多邊形。如果多邊形座標具有 Z 縱座標,則表面是 3 維的。
POLYHEDRALSURFACE Z ( ((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)), ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)), ((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)), ((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)), ((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)) )
三角形是由三個不同的非共線頂點定義的多邊形。由於三角形是一個多邊形,因此它由四個座標指定,其中第一個和第四個座標相等。
TRIANGLE ((0 0, 0 9, 9 0, 0 0))
TIN Z ( ((0 0 0, 0 0 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 0 0 0)) )
ISO/IEC 13249-3 SQL 多媒體 - 空間標準 (SQL/MM) 擴展了 OGC SFA,以定義包含圓弧曲線的幾何子類型。SQL/MM 類型支援 3DM、3DZ 和 4D 座標。
![]() |
|
SQL-MM 實作中的所有浮點比較都是在指定的容差內執行的,目前為 1E-8。 |
圓弧字串是基本的曲線類型,類似於線性世界中的線串。單一弧段由三個點指定:起點和終點 (第一個和第三個) 以及弧上的其他點。若要指定一個封閉的圓,則起點和終點相同,並且中間點是圓直徑上的相對點 (即弧的中心)。在弧序列中,前一個弧的終點是下一個弧的起點,就像線串的線段一樣。這表示圓弧字串必須具有大於 1 的奇數個點。
CIRCULARSTRING(0 0, 1 1, 1 0) CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0)
複合曲線是一個單一的連續曲線,可能包含圓弧段和線段。這表示除了具有良好形成的元件外,每個元件 (最後一個除外) 的終點都必須與後續元件的起點重合。
COMPOUNDCURVE( CIRCULARSTRING(0 0, 1 1, 1 0),(1 0, 0 1))
曲線多邊形與多邊形類似,具有外環和零個或多個內環。不同之處在於,環可以是圓弧字串或複合曲線,也可以是線串。
從 PostGIS 1.4 開始,PostGIS 支援曲線多邊形中的複合曲線。
CURVEPOLYGON( CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0), (1 1, 3 3, 3 1, 1 1) )
範例:一個曲線多邊形,其外殼由包含圓弧字串和線串的複合曲線定義,並且一個孔洞由圓弧字串定義
CURVEPOLYGON( COMPOUNDCURVE( CIRCULARSTRING(0 0,2 0, 2 1, 2 3, 4 3), (4 3, 4 5, 1 4, 0 0)), CIRCULARSTRING(1.7 1, 1.4 0.4, 1.6 0.4, 1.6 0.5, 1.7 1) )
多重曲線是一個曲線的集合,其中可能包括線串、圓弧字串或複合曲線。
MULTICURVE( (0 0, 5 5), CIRCULARSTRING(4 0, 4 4, 8 4))
多重表面是一個表面的集合,可以是 (線性) 多邊形或曲線多邊形。
MULTISURFACE( CURVEPOLYGON( CIRCULARSTRING( 0 0, 4 0, 4 4, 0 4, 0 0), (1 1, 3 3, 3 1, 1 1)), ((10 10, 14 12, 11 10, 10 10), (11 11, 11.5 11, 11 11.5, 11 11)))
OGC SFA 規範定義了兩種用於外部表示幾何值的格式:Well-Known Text (WKT) 和 Well-Known Binary (WKB)。WKT 和 WKB 都包含關於物件類型以及定義它的坐標資訊。
Well-Known Text (WKT) 提供了一種空間數據的標準文字表示法。空間物件的 WKT 表示法範例如下:
POINT(0 0)
POINT Z (0 0 0)
POINT ZM (0 0 0 0)
POINT EMPTY
LINESTRING(0 0,1 1,1 2)
LINESTRING EMPTY
POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))
MULTIPOINT((0 0),(1 2))
MULTIPOINT Z ((0 0 0),(1 2 3))
MULTIPOINT EMPTY
MULTILINESTRING((0 0,1 1,1 2),(2 3,3 2,5 4))
MULTIPOLYGON(((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))
GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4))
GEOMETRYCOLLECTION EMPTY
WKT 的輸入和輸出由 ST_AsText 和 ST_GeomFromText 函數提供。
text WKT = ST_AsText(geometry); geometry = ST_GeomFromText(text WKT, SRID);
例如,一個從 WKT 和 SRID 建立並插入空間物件的語句如下:
INSERT INTO geotable ( geom, name ) VALUES ( ST_GeomFromText('POINT(-126.4 45.32)', 312), 'A Place');
Well-Known Binary (WKB) 提供了一種空間數據的可攜式、全精度表示法,以二進制數據(位元組數組)的形式呈現。空間物件的 WKB 表示法範例如下:
WKT: POINT(1 1)
WKB: 0101000000000000000000F03F000000000000F03
WKT: LINESTRING (2 2, 9 9)
WKB: 0102000000020000000000000000000040000000000000004000000000000022400000000000002240
WKB 的輸入和輸出由 ST_AsBinary 和 ST_GeomFromWKB 函數提供。
bytea WKB = ST_AsBinary(geometry); geometry = ST_GeomFromWKB(bytea WKB, SRID);
例如,一個從 WKB 建立並插入空間物件的語句如下:
INSERT INTO geotable ( geom, name ) VALUES ( ST_GeomFromWKB('\x0101000000000000000000f03f000000000000f03f', 312), 'A Place');
PostGIS 通過定義一個名為 geometry
的 PostgreSQL 數據類型來實現 OGC 簡單要素模型。它通過使用內部類型代碼(請參閱 GeometryType 和 ST_GeometryType)來表示所有幾何子類型。這允許將空間要素建模為定義了 geometry
類型列的表格行。
geometry
數據類型是不透明的,這表示所有訪問都通過調用幾何值上的函數來完成。函數允許建立幾何物件、訪問或更新所有內部字段,並計算新的幾何值。PostGIS 支持 OGC 簡單要素存取 - 第 2 部分:SQL 選項 (SFS) 規範中指定的所有函數,以及許多其他函數。有關函數的完整列表,請參閱第 7 章,PostGIS 參考。
![]() |
|
PostGIS 遵循 SFA 標準,在空間函數前加上 "ST_" 前綴。這原本代表 "Spatial and Temporal"(空間和時間),但該標準的時間部分從未被開發。相反地,它可以被解釋為 "Spatial Type"(空間類型)。 |
SFA 標準指定空間物件包含空間參考系統識別碼 (SRID)。在建立要插入到資料庫中的空間物件時,必須使用 SRID(它可能預設為 0)。請參閱 ST_SRID 和 第 4.5 節,“空間參考系統”。
為了使查詢幾何有效率,PostGIS 定義了各種空間索引和使用它們的空間運算符。有關詳細資訊,請參閱第 4.9 節,“空間索引”和第 5.2 節,“使用空間索引”。
OGC SFA 規範最初僅支持 2D 幾何,並且幾何 SRID 不包含在輸入/輸出表示法中。OGC SFA 規範 1.2.1(與 ISO 19125 標準一致)增加了對 3D (ZYZ) 和測量 (XYM 和 XYZM) 坐標的支持,但仍然不包含 SRID 值。
由於這些限制,PostGIS 定義了擴展的 EWKB 和 EWKT 格式。它們提供 3D (XYZ 和 XYM) 和 4D (XYZM) 坐標支持,並包含 SRID 資訊。包含所有幾何資訊允許 PostGIS 使用 EWKB 作為記錄格式(例如,在 DUMP 文件中)。
EWKB 和 EWKT 用於 PostGIS 數據物件的“規範形式”。對於輸入,二進制數據的規範形式是 EWKB,而對於文本數據,接受 EWKB 或 EWKT。這允許通過使用 ::geometry
將 HEXEWKB 或 EWKT 中的文本值轉換為幾何值來建立幾何值。對於輸出,二進制的規範形式是 EWKB,而文本的規範形式是 HEXEWKB (十六進制編碼的 EWKB)。
例如,以下語句通過從 EWKT 文本值轉換來建立幾何,並使用 HEXEWKB 的規範形式輸出它。
SELECT 'SRID=4;POINT(0 0)'::geometry; geometry ---------------------------------------------------- 01010000200400000000000000000000000000000000000000
PostGIS EWKT 輸出與 OGC WKT 有一些差異:
對於 3DZ 幾何,會省略 Z 限定符。
OGC: POINT Z (1 2 3)
EWKT: POINT (1 2 3)
對於 3DM 幾何,會包含 M 限定符。
OGC: POINT M (1 2 3)
EWKT: POINTM (1 2 3)
對於 4D 幾何,會省略 ZM 限定符。
OGC: POINT ZM (1 2 3 4)
EWKT: POINT (1 2 3 4)
EWKT 避免了過度指定維度,以及 OGC/ISO 格式可能出現的不一致,例如:
POINT ZM (1 1)
POINT ZM (1 1 1)
POINT (1 1 1 1)
![]() |
|
PostGIS 擴展格式目前是 OGC 格式的超集,因此每個有效的 OGC WKB/WKT 也是有效的 EWKB/EWKT。但是,如果 OGC 以與 PosGIS 定義衝突的方式擴展格式,則這種情況可能會在未來發生變化。因此,您不應該依賴這種兼容性! |
空間物件的 EWKT 文本表示法範例如下:
POINT(0 0 0) -- XYZ
SRID=32632;POINT(0 0) -- 帶有 SRID 的 XY
POINTM(0 0 0) -- XYM
POINT(0 0 0 0) -- XYZM
SRID=4326;MULTIPOINTM(0 0 0,1 2 1) -- 帶有 SRID 的 XYM
MULTILINESTRING((0 0 0,1 1 0,1 2 1),(2 3 1,3 2 1,5 4 1))
POLYGON((0 0 0,4 0 0,4 4 0,0 4 0,0 0 0),(1 1 0,2 1 0,2 2 0,1 2 0,1 1 0))
MULTIPOLYGON(((0 0 0,4 0 0,4 4 0,0 4 0,0 0 0),(1 1 0,2 1 0,2 2 0,1 2 0,1 1 0)),((-1 -1 0,-1 -2 0,-2 -2 0,-2 -1 0,-1 -1 0)))
GEOMETRYCOLLECTIONM( POINTM(2 3 9), LINESTRINGM(2 3 4, 3 4 5) )
MULTICURVE( (0 0, 5 5), CIRCULARSTRING(4 0, 4 4, 8 4) )
POLYHEDRALSURFACE( ((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)), ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)), ((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)), ((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)), ((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)) )
TRIANGLE ((0 0, 0 10, 10 0, 0 0))
TIN( ((0 0 0, 0 0 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 0 0 0)) )
可以使用以下函數來進行使用這些格式的輸入和輸出:
bytea EWKB = ST_AsEWKB(geometry); text EWKT = ST_AsEWKT(geometry); geometry = ST_GeomFromEWKB(bytea EWKB); geometry = ST_GeomFromEWKT(text EWKT);
例如,以下語句使用 EWKT 建立並插入 PostGIS 空間物件:
INSERT INTO geotable ( geom, name ) VALUES ( ST_GeomFromEWKT('SRID=312;POINTM(-126.4 45.32 15)'), 'A Place' )
PostGIS geography
數據類型為以“地理”坐標(有時稱為“大地”坐標或“緯度/經度”或“經度/緯度”)表示的空間要素提供原生支援。地理坐標是以角度單位(度)表示的球面坐標。
PostGIS 幾何數據類型的基礎是一個平面。平面上兩點之間的最短路徑是一條直線。這表示幾何上的函數(面積、距離、長度、交點等)是使用直線向量和笛卡爾數學計算的。這使得它們更容易實施且執行速度更快,但也使得它們對於地球橢球表面的數據不夠準確。
PostGIS 地理數據類型基於球面模型。球面上兩點之間的最短路徑是大圓弧。地理上的函數(面積、距離、長度、交點等)是使用球面上的弧線計算的。通過考慮世界的橢球形狀,函數可以提供更準確的結果。
由於底層數學更複雜,因此為地理類型定義的函數比幾何類型少。隨著時間的推移,隨著新演算法的添加,地理類型的功能將會擴展。作為一種變通方法,可以在幾何類型和地理類型之間來回轉換。
與幾何數據類型一樣,地理數據也通過空間參考系統識別碼 (SRID) 與空間參考系統相關聯。可以使用 spatial_ref_sys
表中定義的任何大地(基於經緯度)空間參考系統。(在 PostGIS 2.2 之前,地理類型僅支援 WGS 84 大地 (SRID:4326))。您可以按照第 4.5.2 節,“使用者定義的空間參考系統”中的說明添加您自己的自定義大地空間參考系統。
對於所有空間參考系統,測量函數(例如 ST_Distance、ST_Length、ST_Perimeter、ST_Area)和 ST_DWithin 的距離參數返回的單位均為米。
您可以使用 CREATE TABLE SQL 語句和 geography
類型的列來建立表格以儲存地理數據。以下範例建立了一個包含地理列的表格,該列以 WGS84 大地坐標系統 (SRID 4326) 儲存 2D LineString。
CREATE TABLE global_points ( id SERIAL PRIMARY KEY, name VARCHAR(64), location geography(POINT,4326) );
地理類型支援兩個可選的類型修飾符:
空間類型修飾詞限制了欄位中允許的形狀和維度種類。空間類型允許的值有:POINT、LINESTRING、POLYGON、MULTIPOINT、MULTILINESTRING、MULTIPOLYGON、GEOMETRYCOLLECTION。地理類型不支援曲線、TIN 或 POLYHEDRALSURFACE。此修飾詞透過新增後綴:Z、M 和 ZM 來支援座標維度的限制。例如,修飾詞 'LINESTRINGM' 僅允許具有三個維度的線字串,並將第三個維度視為度量。同樣地,'POINTZM' 需要四維 (XYZM) 資料。
SRID 修飾詞將空間參考系統 SRID 限制為特定數字。如果省略,SRID 預設為 4326(WGS84 大地測量),並且所有計算都使用 WGS84 執行。
建立具有地理欄位的表格範例
建立一個具有預設 SRID 4326 (WGS84 經度/緯度) 的 2D POINT 地理表格
CREATE TABLE ptgeogwgs(gid serial PRIMARY KEY, geog geography(POINT) );
建立一個具有 NAD83 經緯度座標的 2D POINT 地理表格
CREATE TABLE ptgeognad83(gid serial PRIMARY KEY, geog geography(POINT,4269) );
建立一個具有 3D (XYZ) POINT 並明確指定 SRID 為 4326 的表格
CREATE TABLE ptzgeogwgs84(gid serial PRIMARY KEY, geog geography(POINTZ,4326) );
建立一個具有預設 SRID 4326 的 2D LINESTRING 地理表格
CREATE TABLE lgeog(gid serial PRIMARY KEY, geog geography(LINESTRING) );
建立一個具有 SRID 4267 (NAD 1927 經緯度) 的 2D POLYGON 地理表格
CREATE TABLE lgeognad27(gid serial PRIMARY KEY, geog geography(POLYGON,4267) );
地理欄位會在 geography_columns
系統視圖中註冊。您可以查詢 geography_columns
視圖並查看該表格是否已列出
SELECT * FROM geography_columns;
建立空間索引的方式與幾何欄位相同。PostGIS 會注意到欄位類型為 GEOGRAPHY,並建立適當的基於球體的索引,而不是用於 GEOMETRY 的常用平面索引。
-- Index the test table with a spherical index CREATE INDEX global_points_gix ON global_points USING GIST ( location );
您可以像幾何一樣將資料插入地理表格中。如果幾何資料具有 SRID 4326,則會自動轉換為地理類型。EWKT 和 EWKB 格式也可用於指定地理值。
-- Add some data into the test table INSERT INTO global_points (name, location) VALUES ('Town', 'SRID=4326;POINT(-110 30)'); INSERT INTO global_points (name, location) VALUES ('Forest', 'SRID=4326;POINT(-109 29)'); INSERT INTO global_points (name, location) VALUES ('London', 'SRID=4326;POINT(0 49)');
在 spatial_ref_sys
表格中列出的任何大地測量 (經度/緯度) 空間參考系統都可以指定為地理 SRID。如果使用非大地測量座標系統,則會引發錯誤。
-- NAD 83 lon/lat SELECT 'SRID=4269;POINT(-123 34)'::geography; geography ---------------------------------------------------- 0101000020AD1000000000000000C05EC00000000000004140
-- NAD27 lon/lat SELECT 'SRID=4267;POINT(-123 34)'::geography; geography ---------------------------------------------------- 0101000020AB1000000000000000C05EC00000000000004140
-- NAD83 UTM zone meters - gives an error since it is a meter-based planar projection SELECT 'SRID=26910;POINT(-123 34)'::geography; ERROR: Only lon/lat coordinate systems are supported in geography.
查詢和測量函數使用公尺單位。因此,距離參數應以公尺表示,並且傳回值應以公尺(或面積為平方公尺)表示。
-- A distance query using a 1000km tolerance SELECT name FROM global_points WHERE ST_DWithin(location, 'SRID=4326;POINT(-110 29)'::geography, 1000000);
您可以透過計算從西雅圖到倫敦的大圓航線上的飛機 (LINESTRING(-122.33 47.606, 0.0 51.5)) 與雷克雅維克 (POINT(-21.96 64.15)) 之間的距離 (路線地圖) 來了解地理的實際作用。
地理類型計算出雷克雅維克與西雅圖和倫敦之間大圓航線上,球體上的最短距離為 122.235 公里。
-- Distance calculation using GEOGRAPHY SELECT ST_Distance('LINESTRING(-122.33 47.606, 0.0 51.5)'::geography, 'POINT(-21.96 64.15)'::geography); st_distance ----------------- 122235.23815667
幾何類型計算出雷克雅維克與西雅圖到倫敦在世界平面地圖上繪製的直線路徑之間的無意義笛卡爾距離。結果的標稱單位是「度」,但結果不對應於點之間的任何真實角度差,因此即使稱它們為「度」也是不準確的。
-- Distance calculation using GEOMETRY SELECT ST_Distance('LINESTRING(-122.33 47.606, 0.0 51.5)'::geometry, 'POINT(-21.96 64.15)'::geometry); st_distance -------------------- 13.342271221453624
地理資料類型允許您以經度/緯度座標儲存資料,但代價是:GEOGRAPHY 上定義的函數比 GEOMETRY 上的少;那些已定義的函數需要更多 CPU 時間來執行。
您選擇的資料類型應取決於您正在建構的應用程式的預期工作區域。您的資料是跨越全球還是廣大的大陸區域,還是僅限於州、縣或市?
如果您的資料包含在小區域中,您可能會發現就效能和可用功能而言,選擇適當的投影並使用 GEOMETRY 是最佳解決方案。
如果您的資料是全球性的或涵蓋大陸區域,您可能會發現 GEOGRAPHY 允許您建構系統,而無需擔心投影細節。您可以將資料儲存在經度/緯度中,並使用 GEOGRAPHY 上已定義的函數。
如果您不了解投影,並且不想了解投影,並且您準備接受 GEOGRAPHY 中可用功能的限制,那麼對您來說,使用 GEOGRAPHY 可能比 GEOMETRY 更容易。只需將資料以經度/緯度形式載入即可開始使用。
請參閱第 13.11 節「PostGIS 函數支援矩陣」,以比較 Geography 和 Geometry 所支援的內容。如需 Geography 函數的簡要清單和描述,請參閱第 13.4 節「PostGIS 地理支援函數」
4.3.4.1. |
您是在球體上還是橢圓體上進行計算? |
預設情況下,所有距離和面積計算都是在橢圓體上完成的。您應該會發現,在局部區域中的計算結果與在良好局部投影中的局部平面結果相符。在較大區域中,橢圓體計算會比在投影平面上完成的任何計算更準確。 所有地理函數都可以選擇使用球體計算,方法是將最後一個布林參數設定為 'FALSE'。這會稍微加快計算速度,尤其是在幾何形狀非常簡單的情況下。 |
|
4.3.4.2. |
那麼日期變更線和極點呢? |
所有計算都沒有日期變更線或極點的概念,座標是球面的(經度/緯度),因此從計算角度來看,跨越日期變更線的形狀與任何其他形狀沒有任何不同。 |
|
4.3.4.3. |
您可以處理的最長弧線是多少? |
我們使用大圓弧線作為兩點之間的「內插線」。這表示任何兩點實際上都以兩種方式連接,具體取決於您沿著大圓移動的方向。我們所有的程式碼都假設這些點由沿著大圓的兩條路徑中 *較短* 的路徑連接。因此,弧線超過 180 度的形狀將無法正確建模。 |
|
4.3.4.4. |
為什麼計算歐洲/俄羅斯/在此處插入大型地理區域的面積如此緩慢? |
因為多邊形太大了!大面積是不好的,原因有二:它們的邊界很大,因此無論您執行什麼查詢,索引都傾向於提取該特徵;頂點數量很多,並且測試(距離、包含)必須至少遍歷頂點列表一次,有時還需要遍歷 N 次(其中 N 是另一個候選特徵中的頂點數)。 與 GEOMETRY 一樣,我們建議當您有非常大的多邊形,但正在小區域中執行查詢時,您應該將幾何資料「反正規化」為較小的區塊,以便索引可以有效地對物件的各部分執行子查詢,並且查詢不必每次都提取整個物件。請參閱 ST_Subdivide 函數文件。僅僅因為您 *可以* 將整個歐洲儲存在一個多邊形中,並不表示您 *應該* 這樣做。 |
PostGIS 符合開放地理空間協會 (OGC) 的簡單特徵規範。該標準定義幾何形狀為簡單和有效的概念。這些定義允許簡單特徵幾何模型以一致且明確的方式表示空間物件,從而支援高效的計算。(注意:OGC SF 和 SQL/MM 對於簡單和有效具有相同的定義。)
簡單幾何是沒有異常幾何點(例如自相交或自相切)的幾何。
POINT
作為 0 維幾何物件,本質上是簡單的。
如果沒有兩個座標 (POINT
) 相等(具有相同的座標值),則 MULTIPOINT
是簡單的。
如果 LINESTRING
不會兩次穿過同一點(端點除外),則它是簡單的。如果簡單 LineString 的端點相同,則稱為封閉,並稱為線性環。
(a) 和 (c) 是簡單的 |
![]() (a) |
![]() (b) |
![]() (c) |
![]() (d) |
只有當 MULTILINESTRING
的所有元素都是簡單的,並且任意兩個元素之間的唯一交點發生在兩個元素的邊界上的點時,MULTILINESTRING
才是簡單的。
(e) 和 (f) 是簡單的 |
![]() (e) |
![]() (f) |
![]() (g) |
POLYGON
是由線性環形成的,因此有效的多邊形幾何形狀總是簡單的。
若要測試幾何形狀是否簡單,請使用 ST_IsSimple 函數
SELECT ST_IsSimple('LINESTRING(0 0, 100 100)') AS straight, ST_IsSimple('LINESTRING(0 0, 100 100, 100 0, 0 100)') AS crossing; straight | crossing ----------+---------- t | f
一般來說,PostGIS 函數不需要幾何引數是簡單的。簡單性主要用作定義幾何有效性的基礎。它也是某些空間資料模型的要求(例如,線性網路通常不允許交叉的線條)。可以使用 ST_UnaryUnion 使多點和線性幾何形狀簡單化。
幾何有效性主要適用於 2 維幾何形狀(POLYGON
和 MULTIPOLYGON
)。有效性是由允許多邊形幾何形狀明確地模擬平面區域的規則定義的。
如果符合下列條件,則 POLYGON
是有效的
多邊形邊界環(外部外殼環和內部孔環)是簡單的(不交叉或自觸)。因此,多邊形不能有切割線、尖峰或迴路。這表示多邊形孔必須表示為內部環,而不是通過外部環自觸摸(所謂的「反向孔」)。
邊界環不會交叉
邊界環可以在點處接觸,但只能作為切線(即不是在線上)
內部環包含在外部環中
多邊形內部是簡單連接的(即,環的接觸方式不能將多邊形分成多個部分)
(h) 和 (i) 是有效的 |
![]() (h) |
![]() (i) |
![]() (j) |
![]() (k) |
![]() (l) |
![]() (m) |
如果符合下列條件,則 MULTIPOLYGON
是有效的
其元素 POLYGON
是有效的
元素不重疊(即,它們的內部不能相交)
元素僅在點處接觸(即,不是沿著線條)
(n) 是有效的 |
![]() (n) |
![]() (o) |
![]() (p) |
這些規則表示有效的多邊形幾何形狀也是簡單的。
對於線性幾何形狀,唯一的有效性規則是 LINESTRING
必須至少有兩個點且長度不為零(或等效地,至少有兩個不同的點)。請注意,非簡單(自相交)線是有效的。
SELECT ST_IsValid('LINESTRING(0 0, 1 1)') AS len_nonzero, ST_IsValid('LINESTRING(0 0, 0 0, 0 0)') AS len_zero, ST_IsValid('LINESTRING(10 10, 150 150, 180 50, 20 130)') AS self_int; len_nonzero | len_zero | self_int -------------+----------+---------- t | f | t
POINT
和 MULTIPOINT
幾何形狀沒有有效性規則。
PostGIS 允許建立和儲存有效和無效的幾何形狀。這允許偵測和標記或修復無效的幾何形狀。在某些情況下,OGC 有效性規則比預期更嚴格(例如,零長度線字串和具有反向孔的多邊形)。
PostGIS 提供的許多功能都基於幾何參數有效的假設。例如,計算一個孔洞定義在多邊形外部的多邊形面積,或者從非簡單邊界線建構多邊形是沒有意義的。假設有效的幾何輸入可以讓函數更有效率地運作,因為它們不需要檢查拓樸正確性。(值得注意的是,零長度的線和具有反轉的多邊形通常會被正確處理。)此外,如果輸入有效,大多數 PostGIS 函數會產生有效的幾何輸出。這使得 PostGIS 函數可以安全地串聯在一起。
如果您在呼叫 PostGIS 函數時遇到意外的錯誤訊息(例如「GEOS Intersection() 拋出錯誤!」),您應該首先確認函數參數是否有效。如果它們無效,請考慮使用以下技術之一來確保您正在處理的資料有效。
![]() |
|
如果函數回報具有有效輸入的錯誤,那麼您可能在 PostGIS 或它使用的其中一個函式庫中發現錯誤,您應該將此問題回報給 PostGIS 專案。如果 PostGIS 函數針對有效輸入傳回無效的幾何,情況也是如此。 |
要測試幾何是否有效,請使用 ST_IsValid 函數
SELECT ST_IsValid('POLYGON ((20 180, 180 180, 180 20, 20 20, 20 180))'); ----------------- t
ST_IsValidDetail 函數提供有關幾何無效的性質和位置的資訊
SELECT valid, reason, ST_AsText(location) AS location FROM ST_IsValidDetail('POLYGON ((20 20, 120 190, 50 190, 170 50, 20 20))') AS t; valid | reason | location -------+-------------------+--------------------------------------------- f | Self-intersection | POINT(91.51162790697674 141.56976744186045)
在某些情況下,最好自動修正無效的幾何。使用 ST_MakeValid 函數來執行此操作。(ST_MakeValid
是一個允許無效輸入的空間函數的例子!)
預設情況下,PostGIS 在載入幾何時不會檢查有效性,因為有效性測試可能會耗費複雜幾何的大量 CPU 時間。如果您不信任您的資料來源,您可以透過新增檢查約束來強制對您的表格進行有效性檢查
ALTER TABLE mytable ADD CONSTRAINT geometry_valid_check CHECK (ST_IsValid(geom));
空間參考系統 (SRS)(也稱為坐標參考系統 (CRS))定義幾何如何參考地球表面的位置。有三種 SRS 類型
大地測量 SRS 使用角度坐標(經度和緯度),這些坐標直接對應到地球表面。
投影 SRS 使用數學投影轉換,將球體地球的表面「展平」到一個平面上。它以允許直接測量距離、面積和角度等量的方式分配位置坐標。坐標系統是笛卡爾坐標系,這意味著它有一個定義的原點和兩個垂直軸(通常方向為北和東)。每個投影 SRS 都使用指定的長度單位(通常是公尺或英尺)。投影 SRS 的適用區域可能受到限制,以避免失真並符合定義的坐標範圍。
局部 SRS 是一種笛卡爾坐標系統,它不參考地球表面。在 PostGIS 中,這由 SRID 值 0 指定。
有許多不同的空間參考系統正在使用中。常見的 SRS 在歐洲石油調查組織 EPSG 資料庫中標準化。為方便起見,PostGIS(和許多其他空間系統)使用稱為 SRID 的整數識別碼來參考 SRS 定義。
幾何與空間參考系統的關聯是透過其 SRID 值,該值可透過 ST_SRID 存取。幾何的 SRID 可以使用 ST_SetSRID 指派。某些幾何建構函數允許提供 SRID(例如 ST_Point 和 ST_MakeEnvelope)。EWKT 格式使用 SRID=n;
字首支援 SRID。
處理成對幾何的空間函數(例如疊加和關係函數)要求輸入幾何位於相同的空間參考系統中(具有相同的 SRID)。可以使用 ST_Transform 和 ST_TransformPipeline 將幾何資料轉換為不同的空間參考系統。函數傳回的幾何具有與輸入幾何相同的 SRS。
PostGIS 使用的 SPATIAL_REF_SYS
表格是一個符合 OGC 標準的資料庫表格,它定義了可用的空間參考系統。它保存了坐標系統的數值 SRID 和文字描述。
spatial_ref_sys
表格定義如下
CREATE TABLE spatial_ref_sys ( srid INTEGER NOT NULL PRIMARY KEY, auth_name VARCHAR(256), auth_srid INTEGER, srtext VARCHAR(2048), proj4text VARCHAR(2048) )
欄位如下
srid
一個整數程式碼,用於唯一識別資料庫中的空間參考系統 (SRS)。
auth_name
被引用為此參考系統的標準或標準機構的名稱。例如,「EPSG」是一個有效的 auth_name
。
auth_srid
由 auth_name
中引用的機構定義的空間參考系統 ID。就 EPSG 而言,這是 EPSG 程式碼。
srtext
空間參考系統的 Well-Known Text 表示法。WKT SRS 表示法的一個範例是
PROJCS["NAD83 / UTM Zone 10N", GEOGCS["NAD83", DATUM["North_American_Datum_1983", SPHEROID["GRS 1980",6378137,298.257222101] ], PRIMEM["Greenwich",0], UNIT["degree",0.0174532925199433] ], PROJECTION["Transverse_Mercator"], PARAMETER["latitude_of_origin",0], PARAMETER["central_meridian",-123], PARAMETER["scale_factor",0.9996], PARAMETER["false_easting",500000], PARAMETER["false_northing",0], UNIT["metre",1] ]
有關 SRS WKT 的討論,請參閱 OGC 標準坐標參考系統的 Well-known text 表示法。
proj4text
PostGIS 使用 PROJ 函式庫來提供坐標轉換功能。proj4text
欄位包含特定 SRID 的 PROJ 坐標定義字串。例如
+proj=utm +zone=10 +ellps=clrk66 +datum=NAD27 +units=m
如需更多資訊,請參閱PROJ 網站。spatial_ref_sys.sql
檔案包含所有 EPSG 投影的 srtext
和 proj4text
定義。
在擷取用於轉換的空間參考系統定義時,PostGIS 使用以下策略
如果 auth_name
和 auth_srid
存在(非 NULL),請使用基於這些條目的 PROJ SRS(如果存在)。
如果 srtext
存在,請盡可能使用它建立 SRS。
如果 proj4text
存在,請盡可能使用它建立 SRS。
PostGIS spatial_ref_sys
表格包含 3000 多個由 PROJ 投影函式庫處理的最常見空間參考系統定義。但是,它沒有包含許多坐標系統。如果您具有有關空間參考系統的必要資訊,您可以將 SRS 定義新增至表格。或者,如果您熟悉 PROJ 建構,則可以定義自己的自訂空間參考系統。請記住,大多數空間參考系統都是區域性的,在超出其預期範圍使用時沒有意義。
用於尋找核心集中未定義的空間參考系統的資源是http://spatialreference.org/
一些常用的空間參考系統包括:4326 - WGS 84 經緯度、4269 - NAD 83 經緯度、3395 - WGS 84 世界墨卡托、2163 - 美國國家地圖等面積,以及 60 個 WGS84 UTM 區域。UTM 區域是最適合測量的區域之一,但僅涵蓋 6 度的區域。(若要判斷您感興趣區域要使用的 UTM 區域,請參閱utmzone PostGIS plpgsql 輔助函數。)
美國各州使用州平面空間參考系統(基於公尺或英尺)- 通常每個州存在一個或兩個。大多數基於公尺的都在核心集中,但許多基於英尺或 ESRI 建立的都需要從spatialreference.org 複製。
您甚至可以定義非基於地球的坐標系統,例如 Mars 2000。這個火星坐標系統是非平面的(它是以球形度為單位),但是您可以將它與 geography
類型一起使用,以獲得以公尺而不是度為單位的長度和鄰近度測量。
以下範例說明如何使用未指派的 SRID 和以美國為中心的蘭伯特正形投影的 PROJ 定義來載入自訂坐標系統
INSERT INTO spatial_ref_sys (srid, proj4text) VALUES ( 990000, '+proj=lcc +lon_0=-95 +lat_0=25 +lat_1=25 +lat_2=25 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs' );
您可以使用具有 geometry
類型欄位的 CREATE TABLE SQL 陳述式來建立表格以儲存幾何資料。以下範例建立一個表格,其中包含一個幾何欄位,用於儲存 BC-Albers 坐標系統(SRID 3005)中的 2D (XY) LineString
CREATE TABLE roads ( id SERIAL PRIMARY KEY, name VARCHAR(64), geom geometry(LINESTRING,3005) );
geometry
類型支援兩個可選的類型修飾符
使用幾何欄位建立表格的範例
建立一個表格,其中包含具有預設 SRID 的任何種類的幾何
CREATE TABLE geoms(gid serial PRIMARY KEY, geom geometry );
建立一個具有預設 SRID 的 2D POINT 幾何表格
CREATE TABLE pts(gid serial PRIMARY KEY, geom geometry(POINT) );
建立一個具有 3D (XYZ) POINT 和 3005 明確 SRID 的表格
CREATE TABLE pts(gid serial PRIMARY KEY, geom geometry(POINTZ,3005) );
建立一個具有預設 SRID 的 4D (XYZM) LINESTRING 幾何表格
CREATE TABLE lines(gid serial PRIMARY KEY, geom geometry(LINESTRINGZM) );
建立一個具有 SRID 4267(NAD 1927 經緯度)的 2D POLYGON 幾何表格
CREATE TABLE polys(gid serial PRIMARY KEY, geom geometry(POLYGON,4267) );
一個表格中可以有多個幾何欄位。這可以在建立表格時指定,也可以使用 ALTER TABLE SQL 陳述式新增欄位。此範例新增一個可以保存 3D LineString 的欄位
ALTER TABLE roads ADD COLUMN geom2 geometry(LINESTRINGZ,4326);
OGC SQL 簡單要素規範 定義了 GEOMETRY_COLUMNS
元數據表格,用於描述幾何表格結構。在 PostGIS 中,geometry_columns
是一個從資料庫系統目錄表格讀取的視圖。這確保了空間元數據資訊始終與當前定義的表格和視圖保持一致。此視圖的結構如下:
\d geometry_columns
View "public.geometry_columns" Column | Type | Modifiers -------------------+------------------------+----------- f_table_catalog | character varying(256) | f_table_schema | character varying(256) | f_table_name | character varying(256) | f_geometry_column | character varying(256) | coord_dimension | integer | srid | integer | type | character varying(30) |
欄位如下
f_table_catalog, f_table_schema, f_table_name
包含幾何欄位的要素表格的完整名稱。由於 PostgreSQL 沒有「catalog」的對應物,因此該欄位留空。對於「schema」,則使用 PostgreSQL 的 schema 名稱(public
是預設值)。
f_geometry_column
要素表格中幾何欄位的名稱。
coord_dimension
欄位的座標維度(2、3 或 4)。
srid
此表格中用於座標幾何的空間參考系統的 ID。它是對 spatial_ref_sys
表格的外鍵參考(請參閱 第 4.5.1 節,「SPATIAL_REF_SYS 表格」)。
type
空間物件的類型。若要將空間欄位限制為單一類型,請使用以下其中一個:POINT、LINESTRING、POLYGON、MULTIPOINT、MULTILINESTRING、MULTIPOLYGON、GEOMETRYCOLLECTION 或對應的 XYM 版本 POINTM、LINESTRINGM、POLYGONM、MULTIPOINTM、MULTILINESTRINGM、MULTIPOLYGONM、GEOMETRYCOLLECTIONM。對於異質(混合類型)的集合,您可以使用「GEOMETRY」作為類型。
您可能需要這樣做的兩種情況是 SQL 視圖和大量插入。對於大量插入的情況,您可以透過約束欄位或執行 alter table 來修正 geometry_columns 表格中的註冊。對於視圖,您可以使用 CAST 操作來公開。請注意,如果您的欄位是基於 typmod 的,則建立過程會正確註冊它,因此無需執行任何操作。此外,沒有對幾何套用任何空間函數的視圖,也會像底層表格的幾何欄位一樣進行註冊。
-- Lets say you have a view created like this CREATE VIEW public.vwmytablemercator AS SELECT gid, ST_Transform(geom, 3395) As geom, f_name FROM public.mytable; -- For it to register correctly -- You need to cast the geometry -- DROP VIEW public.vwmytablemercator; CREATE VIEW public.vwmytablemercator AS SELECT gid, ST_Transform(geom, 3395)::geometry(Geometry, 3395) As geom, f_name FROM public.mytable; -- If you know the geometry type for sure is a 2D POLYGON then you could do DROP VIEW public.vwmytablemercator; CREATE VIEW public.vwmytablemercator AS SELECT gid, ST_Transform(geom,3395)::geometry(Polygon, 3395) As geom, f_name FROM public.mytable;
--Lets say you created a derivative table by doing a bulk insert SELECT poi.gid, poi.geom, citybounds.city_name INTO myschema.my_special_pois FROM poi INNER JOIN citybounds ON ST_Intersects(citybounds.geom, poi.geom); -- Create 2D index on new table CREATE INDEX idx_myschema_myspecialpois_geom_gist ON myschema.my_special_pois USING gist(geom); -- If your points are 3D points or 3M points, -- then you might want to create an nd index instead of a 2D index CREATE INDEX my_special_pois_geom_gist_nd ON my_special_pois USING gist(geom gist_geometry_ops_nd); -- To manually register this new table's geometry column in geometry_columns. -- Note it will also change the underlying structure of the table to -- to make the column typmod based. SELECT populate_geometry_columns('myschema.my_special_pois'::regclass); -- If you are using PostGIS 2.0 and for whatever reason, you -- you need the constraint based definition behavior -- (such as case of inherited tables where all children do not have the same type and srid) -- set optional use_typmod argument to false SELECT populate_geometry_columns('myschema.my_special_pois'::regclass, false);
雖然仍然支援舊的基於約束的方法,但直接在視圖中使用的基於約束的幾何欄位,將不會在 geometry_columns 中正確註冊,基於 typmod 的也不會。在這個範例中,我們使用 typmod 定義一個欄位,並使用約束定義另一個欄位。
CREATE TABLE pois_ny(gid SERIAL PRIMARY KEY, poi_name text, cat text, geom geometry(POINT,4326)); SELECT AddGeometryColumn('pois_ny', 'geom_2160', 2160, 'POINT', 2, false);
如果我們在 psql 中執行
\d pois_ny;
我們觀察到它們的定義不同 - 一個是 typmod,另一個是約束
Table "public.pois_ny" Column | Type | Modifiers -----------+-----------------------+------------------------------------------------------ gid | integer | not null default nextval('pois_ny_gid_seq'::regclass) poi_name | text | cat | character varying(20) | geom | geometry(Point,4326) | geom_2160 | geometry | Indexes: "pois_ny_pkey" PRIMARY KEY, btree (gid) Check constraints: "enforce_dims_geom_2160" CHECK (st_ndims(geom_2160) = 2) "enforce_geotype_geom_2160" CHECK (geometrytype(geom_2160) = 'POINT'::text OR geom_2160 IS NULL) "enforce_srid_geom_2160" CHECK (st_srid(geom_2160) = 2160)
在 geometry_columns 中,它們都正確註冊
SELECT f_table_name, f_geometry_column, srid, type FROM geometry_columns WHERE f_table_name = 'pois_ny';
f_table_name | f_geometry_column | srid | type -------------+-------------------+------+------- pois_ny | geom | 4326 | POINT pois_ny | geom_2160 | 2160 | POINT
但是,如果我們建立像這樣的視圖
CREATE VIEW vw_pois_ny_parks AS SELECT * FROM pois_ny WHERE cat='park'; SELECT f_table_name, f_geometry_column, srid, type FROM geometry_columns WHERE f_table_name = 'vw_pois_ny_parks';
基於 typmod 的 geom 視圖欄位正確註冊,但基於約束的欄位則沒有。
f_table_name | f_geometry_column | srid | type ------------------+-------------------+------+---------- vw_pois_ny_parks | geom | 4326 | POINT vw_pois_ny_parks | geom_2160 | 0 | GEOMETRY
這在未來的 PostGIS 版本中可能會變更,但目前要強制基於約束的視圖欄位正確註冊,您需要執行以下操作
DROP VIEW vw_pois_ny_parks; CREATE VIEW vw_pois_ny_parks AS SELECT gid, poi_name, cat, geom, geom_2160::geometry(POINT,2160) As geom_2160 FROM pois_ny WHERE cat = 'park'; SELECT f_table_name, f_geometry_column, srid, type FROM geometry_columns WHERE f_table_name = 'vw_pois_ny_parks';
f_table_name | f_geometry_column | srid | type ------------------+-------------------+------+------- vw_pois_ny_parks | geom | 4326 | POINT vw_pois_ny_parks | geom_2160 | 2160 | POINT
建立空間表格後,您就可以將空間資料上傳到資料庫。有兩種內建方式將空間資料放入 PostGIS/PostgreSQL 資料庫:使用格式化的 SQL 陳述式或使用 Shapefile 載入器。
如果空間資料可以轉換為文字表示法(無論是 WKT 或 WKB),則使用 SQL 可能會是將資料放入 PostGIS 的最簡單方式。可以使用 psql
SQL 實用程式載入 SQL INSERT
陳述式的文字檔案,將資料批量載入 PostGIS/PostgreSQL。
SQL 載入檔案(例如 roads.sql
)可能如下所示
BEGIN; INSERT INTO roads (road_id, roads_geom, road_name) VALUES (1,'LINESTRING(191232 243118,191108 243242)','Jeff Rd'); INSERT INTO roads (road_id, roads_geom, road_name) VALUES (2,'LINESTRING(189141 244158,189265 244817)','Geordie Rd'); INSERT INTO roads (road_id, roads_geom, road_name) VALUES (3,'LINESTRING(192783 228138,192612 229814)','Paul St'); INSERT INTO roads (road_id, roads_geom, road_name) VALUES (4,'LINESTRING(189412 252431,189631 259122)','Graeme Ave'); INSERT INTO roads (road_id, roads_geom, road_name) VALUES (5,'LINESTRING(190131 224148,190871 228134)','Phil Tce'); INSERT INTO roads (road_id, roads_geom, road_name) VALUES (6,'LINESTRING(198231 263418,198213 268322)','Dave Cres'); COMMIT;
可以使用 psql
將 SQL 檔案載入 PostgreSQL
psql -d [database] -f roads.sql
shp2pgsql
資料載入器將 Shapefile 轉換為適用於插入 PostGIS/PostgreSQL 資料庫的 SQL,格式可以是幾何或地理。載入器有數種操作模式,可透過命令列標誌選擇。
還有一個 shp2pgsql-gui
圖形介面,其中包含與命令列載入器相同的大部分選項。對於一次性的非腳本載入,或者如果您是 PostGIS 新手,這可能會更容易使用。它也可以設定為 PgAdminIII 的外掛程式。
-c
建立新表格並從 Shapefile 填入資料。這是預設模式。
-a
將 Shapefile 中的資料附加到資料庫表格。請注意,若要使用此選項載入多個檔案,這些檔案必須具有相同的屬性和相同的資料類型。
-d
在建立包含 Shapefile 中資料的新表格之前,先刪除資料庫表格。
-p
僅產生表格建立 SQL 程式碼,而不新增任何實際資料。如果您需要完全分離表格建立和資料載入步驟,則可以使用此功能。
-?
顯示說明畫面。
-D
使用 PostgreSQL「dump」格式輸出資料。這可以與 -a、-c 和 -d 結合使用。它的載入速度比預設的「insert」SQL 格式快得多。對於非常大的資料集,請使用此功能。
-s [<FROM_SRID>:]<SRID>
使用指定的 SRID 建立幾何表格並填入資料。選擇性地指定輸入 shapefile 使用給定的 FROM_SRID,在這種情況下,幾何圖形將會重新投影到目標 SRID。
-k
保留識別碼的大小寫(欄位、schema 和屬性)。請注意,Shapefile 中的屬性全部為大寫。
-i
將所有整數強制轉換為標準 32 位元整數,即使 DBF 標頭簽名似乎需要,也不會建立 64 位元 bigint。
-I
在幾何欄位上建立 GiST 索引。
-m
-m a_file_name
指定一個檔案,其中包含一組(長)欄位名稱到 10 個字元 DBF 欄位名稱的對應關係。檔案內容為一或多行,每行包含兩個名稱,以空格分隔,且沒有前後空格。例如
COLUMNNAME DBFFIELD1 AVERYLONGCOLUMNNAME DBFFIELD2
-S
產生簡單的幾何圖形,而非 MULTI 幾何圖形。僅當所有幾何圖形實際上是單個時(即具有單個殼的 MULTIPOLYGON 或具有單個頂點的 MULTIPOINT)才會成功。
-t <dimensionality>
強制輸出幾何圖形具有指定的維度。使用以下字串來指示維度:2D、3DZ、3DM、4D。
如果輸入的維度少於指定的維度,則輸出將會以零填滿這些維度。如果輸入的維度多於指定的維度,則會移除不需要的維度。
-w
輸出 WKT 格式,而非 WKB。請注意,由於精度損失,這可能會導致座標漂移。
-e
單獨執行每個陳述式,而不使用交易。這樣就可以在存在一些產生錯誤的不良幾何圖形時,載入大部分良好的資料。請注意,這無法與 -D 標誌一起使用,因為「dump」格式始終使用交易。
-W <encoding>
指定輸入資料(dbf 檔案)的編碼。使用時,dbf 的所有屬性都會從指定的編碼轉換為 UTF8。產生的 SQL 輸出將包含 SET CLIENT_ENCODING to UTF8
命令,以便後端能夠從 UTF8 重新轉換為資料庫設定為在內部使用的任何編碼。
-N <policy>
NULL 幾何圖形處理策略 (insert*、skip、abort)
-n
-n 僅匯入 DBF 檔案。如果您的資料沒有對應的 shapefile,它將會自動切換到此模式並僅載入 dbf。因此,只有在您有完整的 shapefile 集,而且您只需要屬性資料而不需要幾何圖形時,才需要設定此標誌。
-G
使用地理類型,而不是幾何類型(需要在 WGS84 經緯度 (SRID=4326) 中使用經緯度資料)
-T <tablespace>
指定新表格的 tablespace。索引仍將使用預設的 tablespace,除非也使用了 -X 參數。PostgreSQL 文件對何時使用自訂 tablespace 有很好的說明。
-X <tablespace>
指定新表格索引的 tablespace。這適用於主索引鍵索引,以及 GIST 空間索引(如果也使用了 -I)。
-Z
使用此標誌時,將防止產生 ANALYZE
陳述式。如果不使用 -Z 標誌(預設行為),則會產生 ANALYZE
陳述式。
使用載入器建立輸入檔案並載入的範例工作階段可能如下所示
# shp2pgsql -c -D -s 4269 -i -I shaperoads.shp myschema.roadstable > roads.sql # psql -d roadsdb -f roads.sql
可以使用 UNIX 管道一步完成轉換和載入
# shp2pgsql shaperoads.shp myschema.roadstable | psql -d roadsdb
可以使用 SQL 或 Shapefile 傾印器從資料庫擷取空間資料。SQL 一節介紹了一些可用於比較和查詢空間表格的函數。
從資料庫擷取空間資料最直接的方法是使用 SQL SELECT
查詢來定義要擷取的資料集,並將產生的欄位傾印到可剖析的文字檔案中
db=# SELECT road_id, ST_AsText(road_geom) AS geom, road_name FROM roads; road_id | geom | road_name --------+-----------------------------------------+----------- 1 | LINESTRING(191232 243118,191108 243242) | Jeff Rd 2 | LINESTRING(189141 244158,189265 244817) | Geordie Rd 3 | LINESTRING(192783 228138,192612 229814) | Paul St 4 | LINESTRING(189412 252431,189631 259122) | Graeme Ave 5 | LINESTRING(190131 224148,190871 228134) | Phil Tce 6 | LINESTRING(198231 263418,198213 268322) | Dave Cres 7 | LINESTRING(218421 284121,224123 241231) | Chris Way (6 rows)
有時需要一些限制來減少傳回的記錄數。在基於屬性的限制的情況下,請使用與非空間表格相同的 SQL 語法。在空間限制的情況下,以下函數很有用
ST_Intersects
此函數會告知兩個幾何圖形是否共享任何空間。
=
這會測試兩個幾何圖形是否在幾何上相同。例如,'POLYGON((0 0,1 1,1 0,0 0))' 是否與 'POLYGON((0 0,1 1,1 0,0 0))' 相同(是的)。
接下來,您可以在查詢中使用這些運算子。請注意,在 SQL 命令列上指定幾何圖形和方塊時,您必須明確地將字串表示法轉換為幾何圖形函數。312 是一個虛構的空間參考系統,與我們的資料相符。所以,例如
SELECT road_id, road_name FROM roads WHERE roads_geom='SRID=312;LINESTRING(191232 243118,191108 243242)'::geometry;
上述查詢會從「ROADS_GEOM」表格傳回單一記錄,其中幾何圖形等於該值。
若要檢查某些道路是否通過多邊形定義的區域
SELECT road_id, road_name FROM roads WHERE ST_Intersects(roads_geom, 'SRID=312;POLYGON((...))');
最常見的空間查詢可能是「基於框架」的查詢,由用戶端軟體(例如資料瀏覽器和 Web 地圖)使用,以抓取「地圖框架」值以供顯示。
當使用「&&」運算子時,您可以指定 BOX3D 或 GEOMETRY 作為比較要素。但是,當您指定 GEOMETRY 時,將會使用其邊界方塊進行比較。
使用「BOX3D」物件作為框架,此類查詢如下所示
SELECT ST_AsText(roads_geom) AS geom FROM roads WHERE roads_geom && ST_MakeEnvelope(191232, 243117,191232, 243119,312);
請注意使用 SRID 312 來指定封套的投影。
pgsql2shp
表格傾印器會連線到資料庫,並將表格(可能是由查詢定義的)轉換為 shapefile。基本語法為
pgsql2shp [<options>] <database> [<schema>.]<table>
pgsql2shp [<options>] <database> <query>
命令列選項如下
-f <filename>
將輸出寫入特定檔案名稱。
-h <host>
要連線的資料庫主機。
-p <port>
要連線的資料庫主機上的埠。
-P <password>
連線到資料庫時要使用的密碼。
-u <user>
連線到資料庫時要使用的使用者名稱。
-g <geometry column>
在具有多個幾何欄位的表格的情況下,寫入 shapefile 時要使用的幾何欄位。
-b
使用二進位游標。這會使操作速度更快,但如果表格中的任何非幾何屬性缺少到文字的轉換,則無法運作。
-r
原始模式。不刪除 gid
欄位,或逸出欄位名稱。
-m filename
將識別碼重新對應為十個字元的名稱。檔案的內容是兩行符號,以單一空格分隔,且沒有前後空格:VERYLONGSYMBOL SHORTONE ANOTHERVERYLONGSYMBOL SHORTER 等。
空間索引使得大型資料集的空間資料庫應用成為可能。若無索引,搜尋要素將需要掃描資料庫中的每一筆記錄。索引透過將資料組織成一種可快速遍歷以尋找匹配記錄的結構,來加速搜尋。
常用於屬性資料的 B 樹索引方法對於空間資料不是非常有用,因為它只支援儲存和查詢單一維度的資料。幾何(具有 2 個或多個維度)等資料需要一種支援跨所有資料維度的範圍查詢的索引方法。PostgreSQL 在空間資料處理方面的主要優勢之一是,它提供了幾種適用於多維資料的索引方法:GiST、BRIN 和 SP-GiST 索引。
GiST (廣義搜尋樹) 索引將資料分解為「一側的事物」、「重疊的事物」、「內部的事物」,並且可用於包括 GIS 資料在內的各種資料類型。PostGIS 使用在 GiST 之上實作的 R 樹索引來索引空間資料。GiST 是最常用且功能最多的空間索引方法,並提供非常好的查詢效能。
BRIN (區塊範圍索引) 索引透過總結表格記錄範圍的空間範圍來運作。搜尋是透過掃描範圍來完成的。BRIN 僅適用於某些類型的資料(空間排序、不常更新或無更新)。但它提供了更快的索引建立時間和更小的索引大小。
SP-GiST (空間分割廣義搜尋樹) 是一種通用索引方法,支援分割搜尋樹,例如四叉樹、k-d 樹和基數樹(字典樹)。
空間索引僅儲存幾何圖形的邊界框。空間查詢使用索引作為主要篩選器,快速判斷一組可能符合查詢條件的幾何圖形。大多數空間查詢都需要次要篩選器,該篩選器使用空間謂詞函數來測試更具體的空間條件。有關使用空間謂詞進行查詢的更多資訊,請參閱第 5.2 節「使用空間索引」。
另請參閱PostGIS Workshop 中關於空間索引的部分,以及PostgreSQL 手冊。
GiST 代表「廣義搜尋樹」,是一種適用於多維資料的通用索引形式。PostGIS 使用在 GiST 之上實作的 R 樹索引來索引空間資料。GiST 是最常用且功能最多的空間索引方法,並提供非常好的查詢效能。GiST 的其他實作被用於加速對各種不規則資料結構(整數陣列、光譜資料等)的搜尋,這些資料結構不適用於正常的 B 樹索引。如需更多資訊,請參閱PostgreSQL 手冊。
一旦空間資料表超過幾千列,您會希望建立索引來加速資料的空間搜尋(除非您的所有搜尋都是基於屬性的,在這種情況下,您需要為屬性欄位建立一個普通索引)。
在「幾何」欄位上建立 GiST 索引的語法如下
CREATE INDEX [indexname] ON [tablename] USING GIST ( [geometryfield] );
上述語法將始終建立 2D 索引。若要取得幾何類型的 n 維索引,您可以使用以下語法建立一個
CREATE INDEX [indexname] ON [tablename] USING GIST ([geometryfield] gist_geometry_ops_nd);
建立空間索引是一項計算密集型的工作。它還會在其建立期間阻止對表格的寫入存取,因此在生產系統上,您可能需要以較慢的 CONCURRENTLY 感知方式進行
CREATE INDEX CONCURRENTLY [indexname] ON [tablename] USING GIST ( [geometryfield] );
建立索引後,有時強制 PostgreSQL 收集表格統計資料會很有幫助,這些統計資料用於最佳化查詢計畫
VACUUM ANALYZE [table_name] [(column_name)];
BRIN 代表「區塊範圍索引」。它是 PostgreSQL 9.5 中引入的通用索引方法。BRIN 是一種有損索引方法,這表示需要進行二次檢查以確認記錄是否符合給定的搜尋條件(所有提供的空間索引都是這種情況)。它提供了更快的索引建立和更小的索引大小,以及合理的讀取效能。其主要目的是支援在與表格內實體位置相關的欄位上索引非常大的表格。除了空間索引外,BRIN 還可以加速對各種屬性資料結構(整數、陣列等)的搜尋。如需更多資訊,請參閱PostgreSQL 手冊。
一旦空間表格超過幾千列,您會希望建立索引來加速資料的空間搜尋。GiST 索引效能非常好,只要它們的大小不超過資料庫可用的 RAM 量,並且只要您可以負擔索引儲存大小以及寫入時的索引更新成本。否則,對於非常大的表格,可以考慮使用 BRIN 索引作為替代方案。
BRIN 索引會儲存一個邊界框,其中包含表格區塊連續集合(稱為區塊範圍)中各列包含的所有幾何圖形。當使用索引執行查詢時,會掃描區塊範圍以尋找與查詢範圍相交的範圍。只有在資料經過實體排序,使得區塊範圍的邊界框具有最小的重疊(理想情況下是互斥的)時,此方法才有效。產生的索引大小非常小,但對於同一資料的讀取效能通常比 GiST 索引差。
建立 BRIN 索引的 CPU 密集程度遠低於建立 GiST 索引。常見的情況是,建立 BRIN 索引的速度比在相同資料上建立 GiST 索引快十倍。由於 BRIN 索引只為每個表格區塊範圍儲存一個邊界框,因此它通常比 GiST 索引少用高達一千倍的磁碟空間。
您可以選擇一個範圍內要總結的區塊數。如果您減少此數字,索引將會更大,但可能會提供更好的效能。
為了使 BRIN 有效,表格資料應以實體順序儲存,以最大限度地減少區塊範圍重疊的數量。資料可能已經以適當的方式排序(例如,如果資料是從已經以空間順序排序的其他資料集載入的)。否則,這可以透過依一維空間金鑰排序資料來完成。一種方法是建立一個按幾何值排序的新表格(在最近的 PostGIS 版本中使用有效率的希爾伯特曲線排序)
CREATE TABLE table_sorted AS SELECT * FROM table ORDER BY geom;
或者,可以使用 GeoHash 作為(臨時)索引並將其叢集化來就地排序資料
CREATE INDEX idx_temp_geohash ON table USING btree (ST_GeoHash( ST_Transform( geom, 4326 ), 20)); CLUSTER table USING idx_temp_geohash;
在 geometry
欄位上建立 BRIN 索引的語法是
CREATE INDEX [indexname] ON [tablename] USING BRIN ( [geome_col] );
上面的語法會建立一個 2D 索引。若要建立 3D 維度索引,請使用此語法
CREATE INDEX [indexname] ON [tablename] USING BRIN ([geome_col] brin_geometry_inclusion_ops_3d);
您也可以使用 4D 運算子類別取得 4D 維度索引
CREATE INDEX [indexname] ON [tablename] USING BRIN ([geome_col] brin_geometry_inclusion_ops_4d);
以上指令使用範圍內的預設區塊數,即 128。若要指定要在範圍內摘要的區塊數,請使用此語法
CREATE INDEX [indexname] ON [tablename] USING BRIN ( [geome_col] ) WITH (pages_per_range = [number]);
請記住,BRIN 索引只為大量的列儲存一個索引項目。如果您的表格儲存具有混合維度數的幾何圖形,則產生的索引可能會效能不佳。您可以透過選擇具有最少儲存幾何圖形維度的運算子類別來避免此效能損失
geography
資料類型支援 BRIN 索引。在 geography 欄位上建立 BRIN 索引的語法為
CREATE INDEX [indexname] ON [tablename] USING BRIN ( [geog_col] );
上面的語法為球體上的地理空間物件建立一個 2D 索引。
目前,僅提供「包含支援」,這表示 2D 案例(對於 geometry
和 geography
兩者)只能使用 &&
、~
和 @
運算子,而 3D 幾何圖形只能使用 &&&
運算子。目前不支援 kNN 搜尋。
BRIN 與其他索引類型之間的一個重要區別是,資料庫不會動態維護索引。對表格中空間資料的變更只是附加到索引的末尾。這會導致索引搜尋效能隨著時間推移而降低。可以透過執行 VACUUM
或使用特殊函數 brin_summarize_new_values(regclass)
來更新索引。因此,BRIN 可能最適合用於唯讀或僅偶爾變更的資料。如需更多資訊,請參閱手冊。
若要使用 BRIN 摘要空間資料
索引建立時間非常快,且索引大小非常小。
索引查詢時間比 GiST 慢,但仍然非常可以接受。
要求表格資料以空間順序排序。
需要手動維護索引。
最適合具有低或無重疊(例如點)、靜態或不常變更的非常大型表格。
對於傳回相對大量資料記錄的查詢更有效。
SP-GiST 代表「空間分割廣義搜尋樹」,是一種適用於多維資料類型的通用索引形式,支援分割搜尋樹,例如四叉樹、k-d 樹和基數樹(字典樹)。這些資料結構的共同特徵是,它們會重複將搜尋空間劃分為大小不必相同的分割區。除了空間索引外,SP-GiST 還用於加速對許多種類資料的搜尋,例如電話路由、IP 路由、子字串搜尋等。如需更多資訊,請參閱PostgreSQL 手冊。
如同 GiST 索引的情況,SP-GiST 索引是有損的,因為它們會儲存包含空間物件的邊界框。SP-GiST 索引可以視為 GiST 索引的替代方案。
一旦 GIS 資料表超過幾千列,就可以使用 SP-GiST 索引來加速資料的空間搜尋。在「幾何」欄位上建立 SP-GiST 索引的語法如下
CREATE INDEX [indexname] ON [tablename] USING SPGIST ( [geometryfield] );
上述語法會建立 2 維索引。可以使用 3D 運算子類別建立幾何類型的 3 維索引
CREATE INDEX [indexname] ON [tablename] USING SPGIST ([geometryfield] spgist_geometry_ops_3d);
建立空間索引是一項計算密集型作業。它還會在其建立期間阻止對表格的寫入存取,因此在生產系統上,您可能需要以較慢的 CONCURRENTLY 感知方式進行
CREATE INDEX CONCURRENTLY [indexname] ON [tablename] USING SPGIST ( [geometryfield] );
建立索引後,有時強制 PostgreSQL 收集表格統計資料會很有幫助,這些統計資料用於最佳化查詢計畫
VACUUM ANALYZE [table_name] [(column_name)];
SP-GiST 索引可以加速涉及以下運算子的查詢
對於 2 維索引,為 <<、&<、&>、>>、<<|、&<|、|&>、|>>、&&、@>、<@ 和 ~=,
對於 3 維索引,為 &/&、~==、@>> 和 <<@。
目前不支援 kNN 搜尋。
通常,索引會隱式地加速資料存取:一旦建立索引,PostgreSQL 查詢規劃器會自動決定何時使用它來改善查詢效能。但在某些情況下,規劃器不會選擇使用現有的索引,因此查詢最終會使用緩慢的循序掃描,而不是空間索引。
如果您發現您的空間索引沒有被使用,您可以執行以下幾項操作
檢查查詢計畫並檢查您的查詢是否實際計算您需要的內容。一個錯誤的 JOIN,無論是遺忘的還是針對錯誤的表格,都可能會意外地多次檢索表格記錄。若要取得查詢計畫,請在查詢前面執行 EXPLAIN
。
請務必收集表格中數值數量和分佈的統計資料,以便為查詢規劃器提供更好的資訊,來決定索引的使用方式。VACUUM ANALYZE 指令將會計算這兩者。
無論如何,您都應該定期清理您的資料庫。許多 PostgreSQL 資料庫管理員都會定期在離峰時間以 cron job 執行 VACUUM 指令。
如果清理沒有幫助,您可以暫時使用 SET ENABLE_SEQSCAN TO OFF; 指令強制規劃器使用索引資訊。這樣您可以檢查規劃器是否能夠為您的查詢產生使用索引加速的查詢計畫。您應該只將此指令用於除錯;一般來說,規劃器比您更清楚何時該使用索引。執行您的查詢後,不要忘記執行 SET ENABLE_SEQSCAN TO ON;,讓規劃器可以正常處理其他查詢。
如果 SET ENABLE_SEQSCAN TO OFF; 有助於加快查詢速度,您的 Postgres 可能沒有針對您的硬體進行調整。如果您發現規劃器在判斷循序掃描與索引掃描的成本時出錯,請嘗試在 postgresql.conf
中降低 RANDOM_PAGE_COST
的值,或使用 SET RANDOM_PAGE_COST TO 1.1;。 RANDOM_PAGE_COST
的預設值為 4.0。嘗試將其設定為 1.1(適用於 SSD)或 2.0(適用於快速磁碟)。降低該值會使規劃器更傾向於使用索引掃描。
如果 SET ENABLE_SEQSCAN TO OFF; 沒有幫助您的查詢,則該查詢可能正在使用 Postgres 規劃器尚未能最佳化的 SQL 結構。或許可以透過改寫查詢的方式,使其能被規劃器處理。例如,帶有內聯 SELECT 的子查詢可能無法產生有效率的計畫,但可以使用 LATERAL JOIN 改寫。
如需更多資訊,請參閱 Postgres 手冊中關於查詢規劃的章節。