Planetary-scale answers, unlocked.
A Hands-On Guide for Working with Large-Scale Spatial Data. Learn more.
A geospatial database is a database that stores the shapes and locations of things on Earth and answers questions about them in SQL. It has three parts: geometry types, a spatial index, and spatial SQL functions. This article tests one claim about those parts: the spatial index, or the bounding boxes a table format stores for each file, sets how much data a spatial query reads. On 2,533,842,612 Overture buildings in Wherobots, a filter the scan could use limited the read to 7 of 5,141 files.
bbox
Ralf Hartmut Güting gave the classic geospatial database definition in An introduction to spatial database systems (The VLDB Journal, 1994). A spatial database system is a database system first. It offers spatial data types in its data model and query language. Its implementation supports those types with, at least, spatial indexing and efficient spatial join algorithms. The PostGIS workshop on spatial indexing calls the spatial index "one of the three key features of a spatial database".
Spatial database and geospatial database often mean the same thing. A spatial database can store shapes on any plane, including one with no units. A geospatial database ties coordinates to the Earth through a coordinate reference system (CRS), the definition that places each coordinate on the planet.
A GIS (geographic information system) is software for viewing, editing and analyzing map layers. A geospatial database stores those layers as tables and answers queries from many programs, including a GIS. Our article on geospatial data covers the data itself.
Geospatial database management is the work around the three parts. The PostGIS data management chapter covers it: geometry types, reference systems, validation, loading, and spatial indexes.
Most geospatial databases share one geometry model. The Open Geospatial Consortium (OGC), a standards body for geospatial data, publishes it as Simple Feature Access, Part 1: Common Architecture. The International Organization for Standardization (ISO) publishes the same model as ISO 19125. Its base Geometry class has four subclasses: Point, Curve, Surface and GeometryCollection. Each geometry belongs to a spatial reference system.
The PostGIS manual lists the concrete types:
Each geometry also has an envelope, the smallest upright box that contains it. Wherobots' Havasu documentation calls it the minimum bounding rectangle (MBR), or bounding box. Every index in the next section works on these boxes. Part 2 of the standard, the SQL option, defines a SQL schema to store, retrieve, query and update features.
Vector types describe discrete features. Raster data stores a grid of cells, such as a satellite image. The Havasu table spec defines a raster type beside the geometry type, and raster vs vector data compares the two models.
One query on three Overture Maps tables shows the vector types in use. The box around King County, Washington, runs from longitude -122.6 to -120.9 and latitude 47.0 to 47.8. Overture stores each feature's bounding box in a bbox column.
SELECT 'buildings_building' AS source, ST_GeometryType(geometry) AS geometry_type, COUNT(*) AS features FROM wherobots_open_data.overture_maps_foundation.buildings_building WHERE bbox.xmin >= -122.6 AND bbox.xmax <= -120.9 AND bbox.ymin >= 47.0 AND bbox.ymax <= 47.8 GROUP BY ST_GeometryType(geometry) UNION ALL SELECT 'places_place', ST_GeometryType(geometry), COUNT(*) FROM wherobots_open_data.overture_maps_foundation.places_place WHERE bbox.xmin >= -122.6 AND bbox.xmax <= -120.9 AND bbox.ymin >= 47.0 AND bbox.ymax <= 47.8 GROUP BY ST_GeometryType(geometry) UNION ALL SELECT 'transportation_segment', ST_GeometryType(geometry), COUNT(*) FROM wherobots_open_data.overture_maps_foundation.transportation_segment WHERE bbox.xmin >= -122.6 AND bbox.xmax <= -120.9 AND bbox.ymin >= 47.0 AND bbox.ymax <= 47.8 GROUP BY ST_GeometryType(geometry)
Buildings are polygons, places are points, and road segments are lines.
A B-tree, the usual database index, sorts rows by one value. A location has two values, longitude and latitude. A B-tree on either one returns a whole strip of the map.
Spatial indexes work on bounding boxes. The PostGIS workshop describes two passes: the index finds features whose boxes overlap the query box, then an exact test runs on those features only. Oracle documents the same two-tier query model. Our spatial join article shows how joins use these filter and refine steps.
Havasu, the Wherobots table format built on Iceberg, records each file's MBR at write time. According to the Havasu clustering documentation, a query then skips every file whose MBR misses its spatial filter. Wherobots calls this spatial filter push-down.
Box indexes share one condition. The PostGIS manual says a BRIN index is efficient only if the boxes of the block ranges overlap little. The Havasu documentation says push-down "works best when the spatial data near to each other were stored in the same file". In both, the order of rows on disk sets how much a query can skip. The PostGIS manual adds a cost: GiST indexes perform well while they fit in memory and their update cost on each write is acceptable.
Spatial SQL is SQL with functions that take or return geometry. Most systems name them with an ST_ prefix. Constructors such as ST_GeomFromText read well-known text (WKT), a plain-text geometry format. Measurements include ST_Area and ST_Distance. Predicates are true or false tests such as ST_Intersects and ST_Contains. Operations such as ST_Buffer and ST_Union return new geometry.
Two standards define them: the OGC SQL option, and ISO/IEC 13249-3, SQL Multimedia Part 3: Spatial (SQL/MM Spatial). PostGIS uses SQL/MM for curved types with circular arcs. The OGC group that maintains Simple Features is working to synchronize it with SQL/MM Part 3.
The predicates come from topology research. Max Egenhofer and Robert Franzosa's Point-set topological spatial relations (International Journal of Geographical Information Systems, 1991) defined the relations between two regions from their boundaries and interiors.
Only some predicates use an index. The PostGIS workshop lists the functions that use one automatically, among them ST_Intersects, ST_Contains, ST_Within and ST_DWithin. The index holds boxes of the stored geometry. It has no entries for a value computed at query time, such as the longitude of a building's centroid. The Wherobots test below measures what that costs on a data lake table.
A familiar geospatial database example is PostGIS. Each description below comes from the product's own documentation or paper.
A distributed engine splits a table into partitions and processes them on many machines at once.
A format stores spatial data, and an engine queries it. GeoParquet is an incubating OGC standard that adds geospatial types to Apache Parquet, a column-oriented file format. Apache Iceberg is a table format: metadata that groups many Parquet files into one table with per-file statistics. The Havasu Catalog article explains how Wherobots catalogs such tables.
Object storage is cloud file storage, such as Amazon S3, that many machines read at once. A spatial partition is a region of the map whose features go to one worker. The partitioning tax article covers the edges between partitions.
Choosing a database for geospatial data starts with the workload. There is no single best geospatial database. These rules match workloads to the system types in the table:
The test below checks rule 5 on one table.
The .files table is an Apache Iceberg metadata table, with one row per data file. Each row holds the file's row count, size, and lower and upper bounds for each column. Reading it opens no data file.
.files
SELECT COUNT(*) AS files, SUM(record_count) AS rows, ROUND(SUM(file_size_in_bytes) / 1e9, 1) AS gb FROM wherobots_open_data.overture_maps_foundation.buildings_building.files
The buildings table has 5,141 files holding 2,533,842,612 rows and 253.2 GB. The next query counts the files whose bbox bounds overlap the King County box:
WITH f AS ( SELECT record_count, file_size_in_bytes AS bytes, readable_metrics.`bbox.xmin`.lower_bound AS xmin, readable_metrics.`bbox.xmax`.upper_bound AS xmax, readable_metrics.`bbox.ymin`.lower_bound AS ymin, readable_metrics.`bbox.ymax`.upper_bound AS ymax FROM wherobots_open_data.overture_maps_foundation.buildings_building.files ) SELECT COUNT(*) AS files_total, SUM(CASE WHEN xmin IS NULL THEN 1 ELSE 0 END) AS files_without_bounds, SUM(CASE WHEN xmax >= -122.6 AND xmin <= -120.9 AND ymax >= 47.0 AND ymin <= 47.8 THEN 1 ELSE 0 END) AS files_touching_king_county_box, SUM(CASE WHEN xmax >= -122.6 AND xmin <= -120.9 AND ymax >= 47.0 AND ymin <= 47.8 THEN record_count ELSE 0 END) AS rows_in_those_files, ROUND(SUM(CASE WHEN xmax >= -122.6 AND xmin <= -120.9 AND ymax >= 47.0 AND ymin <= 47.8 THEN bytes ELSE 0 END) / 1e9, 2) AS gb_in_those_files FROM f
Every file has bounds, and 7 overlap the box. The query ran in 2.9 seconds. Five of the 7 files cover parts of western Washington. One of the other two spans longitude -179.80 to -90.10 and latitude 23.87 to 79.42, with 517,022 rows. The Havasu Catalog article found a file with the same bounds near Lake Havasu City, Arizona. The last spans longitude -122.54 to -2.06 and latitude -7.74 to 70.85, with 599,661 rows.
SELECT COUNT(*) AS buildings_in_box FROM wherobots_open_data.overture_maps_foundation.buildings_building WHERE bbox.xmin >= -122.6 AND bbox.xmax <= -120.9 AND bbox.ymin >= 47.0 AND bbox.ymax <= 47.8
The query returned 1,283,332 buildings whose bounding box lies inside the King County box, in 5.4 seconds. EXPLAIN FORMATTED prints the query plan, the steps WherobotsDB runs. The plan's scan line holds the four bounds:
EXPLAIN FORMATTED
IcebergScan(table=...buildings_building, ..., filters=bbox.xmin IS NOT NULL, ..., bbox.xmin >= -122.6, bbox.xmax <= -120.9, bbox.ymin >= 47.0, bbox.ymax <= 47.8, ...)
A filter inside IcebergScan is compared with each file's bounds before the file opens. Files whose bounds miss the box are skipped, so the scan reads at most the 7 files from Query 1.
IcebergScan
This version tests each building's centroid, computed from the geometry with ST_Centroid, ST_X and ST_Y:
EXPLAIN FORMATTED SELECT COUNT(*) AS buildings_in_box FROM wherobots_open_data.overture_maps_foundation.buildings_building WHERE ST_X(ST_Centroid(geometry)) BETWEEN -122.6 AND -120.9 AND ST_Y(ST_Centroid(geometry)) BETWEEN 47.0 AND 47.8
The scan line now has an empty filter, and a separate Filter step follows the scan:
Filter
IcebergScan(table=...buildings_building, ..., filters=, runtimeFilters=, ...) Filter (ST_X(ST_Centroid(geometry)) ... ST_Y(ST_Centroid(geometry)) ...)
With no filter in the scan, all 5,141 files (253.2 GB) would be read, and a centroid computed for each of 2,533,842,612 rows before the box test. We ran EXPLAIN only, to avoid a full read on a small shared session.
EXPLAIN
A spatial join matches rows of two tables by a spatial predicate. This one assigns each building's centroid to the Washington county polygon that contains it:
WITH county AS ( SELECT names.primary AS county, geometry AS g FROM wherobots_open_data.overture_maps_foundation.divisions_division_area WHERE country = 'US' AND region = 'US-WA' AND subtype = 'county' AND class = 'land' ), b AS ( SELECT ST_Centroid(geometry) AS c FROM wherobots_open_data.overture_maps_foundation.buildings_building WHERE bbox.xmin >= -122.6 AND bbox.xmax <= -120.9 AND bbox.ymin >= 47.0 AND bbox.ymax <= 47.8 ) SELECT /*+ BROADCAST(county) */ county.county, COUNT(*) AS buildings FROM b JOIN county ON ST_Intersects(county.g, b.c) GROUP BY county.county ORDER BY buildings DESC
The join ran in 14.8 seconds. The other counties extend past the box, so their counts cover only the part inside it. The plan shows BroadcastIndexJoin ... INTERSECTS with SpatialIndex g: geometry, RTREE. The BROADCAST hint copies the small table, the county polygons, to every worker. WherobotsDB builds an R-tree on those polygons and tests the 1,283,332 building centroids against it. The spatial join article compares broadcast and partitioned joins, and the nearest-neighbor join announcement covers a related join type.
BroadcastIndexJoin ... INTERSECTS
SpatialIndex g: geometry, RTREE
BROADCAST
The results support the claim. A box filter the scan could use left 7 of 5,141 files, 0.46 GB of 253.2 GB. The same box as a centroid test left the scan with no filter and all 5,141 files to read. In the spatial join, WherobotsDB built an R-tree and counted 845,001 buildings in King County. The bounds are coarse, though: the 7 files hold 3,702,731 rows for 1,283,332 results, and two of them span most of a continent. That matches the Havasu documentation's condition that nearby features share files.
The first OGC specification for spatial SQL was the Simple Features Implementation Specification for SQL 1.1 (OGC document 99-049). Both parts of Simple Feature Access now stand at version 1.2.1. The working group that maintains them is adding new geometry types and support for 3D coordinates.
Jignesh Patel and David DeWitt's Partition based spatial-merge join (ACM SIGMOD, 1996) joined two inputs that have no index by splitting both into spatial partitions. Hadoop-GIS and SpatialHadoop carried partitioning and indexing to clusters. Yu, Zongsi Zhang and Sarwat described GeoSpark's partitioning, indexing and joins in Spatial data management in Apache Spark: the GeoSpark perspective and beyond (GeoInformatica, 2018). GeoSpark became Apache Sedona.
The newest step puts geometry into open table formats, with bounding boxes per file. In the Iceberg spec, a geometry column with no stated CRS stores longitude and latitude on the World Geodetic System 1984 (WGS 84) datum, named OGC:CRS84. Wherobots described its own format in Havasu: a table format for spatial attributes in a data lake architecture.
ST_Intersects
CREATE SPATIAL INDEX
Query Overture buildings with spatial SQL in a Wherobots free trial at cloud.wherobots.com.
A geospatial database is a database that stores the shapes and locations of things on Earth and answers questions about them. It has three parts. Geometry types store points, lines and polygons. A spatial index finds the rows in an area without reading every row. Spatial SQL functions, such as ST_Intersects and ST_Distance, ask the questions.
PostGIS, which adds geometry types, spatial indexes and spatial functions to the PostgreSQL database, is a common example. Others are Oracle Spatial, the geometry and geography types in Microsoft SQL Server, SpatiaLite for SQLite, and the geography type in Google BigQuery. Apache Sedona and WherobotsDB run spatial SQL across a cluster of machines.
The best choice depends on the workload. For many small edits to single features, use a relational database with spatial types, such as PostGIS. For one user or one app, a single file such as SpatiaLite or GeoParquet works. For billions of rows or joins between large tables, use a distributed engine such as Apache Sedona or WherobotsDB over files with per-file bounding boxes.
The usual answer is vector data, raster data and attribute data. Vector data stores features as points, lines and polygons. Raster data stores a grid of cells, such as a satellite image. Attribute data is the table of facts about each feature, such as a building’s height. Within vector data, points, lines and polygons are also called the three geometry types.
The terms are often used for the same thing. A spatial database can store shapes in any coordinate space, including a plane with no units. A geospatial database ties coordinates to places on Earth through a coordinate reference system, such as longitude and latitude on WGS 84, the World Geodetic System 1984 that GPS uses.
A GIS (geographic information system) is software for viewing, editing and analyzing map layers, often on a desktop. A geospatial database stores those layers in tables and answers queries from many programs. A GIS often reads its layers from a geospatial database.
Spatial SQL is SQL with functions that take or return geometry. Most systems name them with an ST_ prefix: ST_Intersects and ST_Contains test how two shapes relate, ST_Area and ST_Distance measure, and ST_Buffer and ST_Union build new shapes. The Simple Features SQL option of the Open Geospatial Consortium (OGC) and ISO/IEC 13249-3 (SQL/MM Spatial) define them.
Yes. PostGIS is an extension of the PostgreSQL relational database. It adds geometry and geography types, spatial indexes (an R-tree on GiST, a quadtree on SP-GiST, and BRIN boxes per block range), and spatial SQL functions. It also stores raster data.
Yes, when a table format stores geometry and per-file bounds and an engine runs spatial SQL over it. Apache Iceberg version 3 adds geometry and geography types with a bounding box for each data file. In Wherobots, a box filter on 2,533,842,612 Overture buildings used those bounds to limit the read to 7 of 5,141 files.
Geospatial database management is the work of running a spatial database. It covers loading data, choosing coordinate reference systems, validating geometry and building spatial indexes. It also covers storing nearby features together, which sets how many files or blocks an area query can skip.
What is an Isochrone? Isochrone Maps and Travel Time
An isochrone is the area reachable from a place within a set travel time. How isochrones are computed, isochrone vs radius, and a King County test.
What is a Map Projection? Types, Distortion, Examples
A map projection flattens the Earth onto a map and distorts area, shape, distance or direction. Projection types, examples, and how to choose one.
What is Geospatial Intelligence? GEOINT Defined, Examples
Geospatial intelligence (GEOINT) analyzes imagery and map data to describe activity on earth. Definition, history, examples, and a New Orleans walkthrough.
share this article
Awesome that you’d like to share our articles. Where would you like to share it to: